FLANG
DirectivesCommon.h
1//===-- Lower/DirectivesCommon.h --------------------------------*- 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//===----------------------------------------------------------------------===//
16//===----------------------------------------------------------------------===//
17
18#ifndef FORTRAN_LOWER_DIRECTIVES_COMMON_H
19#define FORTRAN_LOWER_DIRECTIVES_COMMON_H
20
21#include "flang/Evaluate/tools.h"
22#include "flang/Lower/AbstractConverter.h"
23#include "flang/Lower/Bridge.h"
24#include "flang/Lower/ConvertVariable.h"
25#include "flang/Lower/OpenACC.h"
26#include "flang/Lower/OpenMP.h"
27#include "flang/Lower/PFTBuilder.h"
28#include "flang/Lower/StatementContext.h"
29#include "flang/Lower/Support/Utils.h"
30#include "flang/Optimizer/Builder/DirectivesCommon.h"
31#include "flang/Optimizer/Builder/HLFIRTools.h"
32#include "flang/Optimizer/Dialect/FIRType.h"
33#include "flang/Parser/parse-tree.h"
34#include "flang/Semantics/tools.h"
35#include "mlir/IR/Value.h"
36#include <list>
37#include <type_traits>
38
39namespace Fortran {
40namespace lower {
41
44template <typename... TerminatorOps>
46 fir::FirOpBuilder &builder,
47 std::list<Fortran::lower::pft::Evaluation> &evaluationList) {
48 mlir::Region *region = &builder.getRegion();
49 for (Fortran::lower::pft::Evaluation &eval : evaluationList) {
50 if (eval.block) {
51 if (eval.block->empty()) {
52 eval.block->erase();
53 eval.block = builder.createBlock(region);
54 } else {
55 [[maybe_unused]] mlir::Operation &terminatorOp = eval.block->back();
56 assert(mlir::isa<TerminatorOps...>(terminatorOp) &&
57 "expected terminator op");
58 }
59 }
60 if (!eval.isDirective() && eval.hasNestedEvaluations())
61 createEmptyRegionBlocks<TerminatorOps...>(builder,
62 eval.getNestedEvaluations());
63 }
64}
65
67getDataOperandBaseAddr(Fortran::lower::AbstractConverter &converter,
68 fir::FirOpBuilder &builder,
69 Fortran::lower::SymbolRef sym, mlir::Location loc,
70 bool unwrapFirBox = true) {
71 return fir::factory::getDataOperandBaseAddr(
72 builder, converter.getSymbolAddress(sym),
73 Fortran::semantics::IsOptional(sym), loc, unwrapFirBox);
74}
75
76namespace detail {
77template <typename T> //
78static T &&AsRvalueRef(T &&t) {
79 return std::move(t);
80}
81template <typename T> //
82static T AsRvalueRef(T &t) {
83 return t;
84}
85template <typename T> //
86static T AsRvalueRef(const T &t) {
87 return t;
88}
89
90// Helper class for stripping enclosing parentheses and a conversion that
91// preserves type category. This is used for triplet elements, which are
92// always of type integer(kind=8). The lower/upper bounds are converted to
93// an "index" type, which is 64-bit, so the explicit conversion to kind=8
94// (if present) is not needed. When it's present, though, it causes generated
95// names to contain "int(..., kind=8)".
97 template <Fortran::common::TypeCategory Category, int Kind>
98 static Fortran::semantics::MaybeExpr visit_with_category(
100 &expr) {
101 return Fortran::common::visit(
102 [](auto &&s) { return visit_with_category<Category, Kind>(s); },
103 expr.u);
104 }
105 template <Fortran::common::TypeCategory Category, int Kind>
106 static Fortran::semantics::MaybeExpr visit_with_category(
108 Category> &expr) {
109 return AsGenericExpr(AsRvalueRef(expr.left()));
110 }
111 template <Fortran::common::TypeCategory Category, int Kind, typename T>
112 static Fortran::semantics::MaybeExpr visit_with_category(const T &) {
113 return std::nullopt; //
114 }
115 template <Fortran::common::TypeCategory Category, typename T>
116 static Fortran::semantics::MaybeExpr visit_with_category(const T &) {
117 return std::nullopt; //
118 }
119
120 template <Fortran::common::TypeCategory Category>
121 static Fortran::semantics::MaybeExpr
123 &expr) {
124 return Fortran::common::visit(
125 [](auto &&s) { return visit_with_category<Category>(s); }, expr.u);
126 }
127 static Fortran::semantics::MaybeExpr
129 return Fortran::common::visit([](auto &&s) { return visit(s); }, expr.u);
130 }
131 template <typename T> //
132 static Fortran::semantics::MaybeExpr visit(const T &) {
133 return std::nullopt;
134 }
135};
136
137static inline Fortran::semantics::SomeExpr
138peelOuterConvert(Fortran::semantics::SomeExpr &expr) {
139 if (auto peeled = PeelConvert::visit(expr))
140 return *peeled;
141 return expr;
142}
143} // namespace detail
144
147template <typename BoundsOp, typename BoundsType>
149genBoundsOps(fir::FirOpBuilder &builder, mlir::Location loc,
152 const std::vector<Fortran::evaluate::Subscript> &subscripts,
153 std::stringstream &asFortran, fir::ExtendedValue &dataExv,
154 bool dataExvIsAssumedSize, fir::factory::AddrAndBoundsInfo &info,
155 bool treatIndexAsSection = false,
156 bool strideIncludeLowerExtent = false) {
157 int dimension = 0;
158 mlir::Type idxTy = builder.getIndexType();
159 mlir::Type boundTy = builder.getType<BoundsType>();
161
162 mlir::Value zero = builder.createIntegerConstant(loc, idxTy, 0);
163 mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1);
164 const int dataExvRank = static_cast<int>(dataExv.rank());
165 mlir::Value cumulativeExtent = one;
166 for (const auto &subscript : subscripts) {
167 const auto *triplet{std::get_if<Fortran::evaluate::Triplet>(&subscript.u)};
168 if (triplet || treatIndexAsSection) {
169 if (dimension != 0)
170 asFortran << ',';
171 mlir::Value lbound, ubound, extent;
172 std::optional<std::int64_t> lval, uval;
173 mlir::Value baseLb =
174 fir::factory::readLowerBound(builder, loc, dataExv, dimension, one);
175 bool defaultLb = baseLb == one;
176 mlir::Value stride = one;
177 bool strideInBytes = false;
178
179 auto genSourceExtent = [&]() -> mlir::Value {
180 if (info.isPresent && mlir::isa<fir::BaseBoxType>(
181 fir::unwrapRefType(info.addr.getType()))) {
182 return builder
183 .genIfOp(loc, idxTy, info.isPresent, /*withElseRegion=*/true)
184 .genThen([&]() {
185 mlir::Value ext =
186 fir::factory::readExtent(builder, loc, dataExv, dimension);
187 fir::ResultOp::create(builder, loc, ext);
188 })
189 .genElse([&] {
190 mlir::Value zero = builder.createIntegerConstant(loc, idxTy, 0);
191 fir::ResultOp::create(builder, loc, zero);
192 })
193 .getResults()[0];
194 }
195 return fir::factory::readExtent(builder, loc, dataExv, dimension);
196 };
197
198 if (mlir::isa<fir::BaseBoxType>(
199 fir::unwrapRefType(info.addr.getType()))) {
200 if (info.isPresent) {
201 stride =
202 builder
203 .genIfOp(loc, idxTy, info.isPresent, /*withElseRegion=*/true)
204 .genThen([&]() {
205 mlir::Value box =
206 !fir::isBoxAddress(info.addr.getType())
207 ? info.addr
208 : fir::LoadOp::create(builder, loc, info.addr);
209 mlir::Value d =
210 builder.createIntegerConstant(loc, idxTy, dimension);
211 auto dimInfo = fir::BoxDimsOp::create(builder, loc, idxTy,
212 idxTy, idxTy, box, d);
213 fir::ResultOp::create(builder, loc,
214 dimInfo.getByteStride());
215 })
216 .genElse([&] {
217 mlir::Value zero =
218 builder.createIntegerConstant(loc, idxTy, 0);
219 fir::ResultOp::create(builder, loc, zero);
220 })
221 .getResults()[0];
222 } else {
223 mlir::Value box = !fir::isBoxAddress(info.addr.getType())
224 ? info.addr
225 : fir::LoadOp::create(builder, loc, info.addr);
226 mlir::Value d = builder.createIntegerConstant(loc, idxTy, dimension);
227 auto dimInfo =
228 fir::BoxDimsOp::create(builder, loc, idxTy, idxTy, idxTy, box, d);
229 stride = dimInfo.getByteStride();
230 }
231 strideInBytes = true;
232 }
233
234 Fortran::semantics::MaybeExpr lower;
235 if (triplet) {
236 lower = Fortran::evaluate::AsGenericExpr(triplet->lower());
237 } else {
238 // Case of IndirectSubscriptIntegerExpr
239 using IndirectSubscriptIntegerExpr =
240 Fortran::evaluate::IndirectSubscriptIntegerExpr;
241 using SubscriptInteger = Fortran::evaluate::SubscriptInteger;
243 std::get<IndirectSubscriptIntegerExpr>(subscript.u).value();
244 lower = Fortran::evaluate::AsGenericExpr(std::move(oneInt));
245 if (lower->Rank() > 0) {
246 mlir::emitError(
247 loc, "vector subscript cannot be used for an array section");
248 break;
249 }
250 }
251 if (lower) {
252 lval = Fortran::evaluate::ToInt64(*lower);
253 if (lval) {
254 if (defaultLb) {
255 lbound = builder.createIntegerConstant(loc, idxTy, *lval - 1);
256 } else {
257 mlir::Value lb = builder.createIntegerConstant(loc, idxTy, *lval);
258 lbound = mlir::arith::SubIOp::create(builder, loc, lb, baseLb);
259 }
260 asFortran << *lval;
261 } else {
262 mlir::Value lb =
263 fir::getBase(converter.genExprValue(loc, *lower, stmtCtx));
264 lb = builder.createConvert(loc, baseLb.getType(), lb);
265 lbound = mlir::arith::SubIOp::create(builder, loc, lb, baseLb);
266 asFortran << detail::peelOuterConvert(*lower).AsFortran();
267 }
268 } else {
269 // If the lower bound is not specified, then the section
270 // starts from offset 0 of the dimension.
271 // Note that the lowerbound in the BoundsOp is always 0-based.
272 lbound = zero;
273 }
274
275 if (!triplet) {
276 // If it is a scalar subscript, then the upper bound
277 // is equal to the lower bound, and the extent is one.
278 ubound = lbound;
279 extent = one;
280 } else {
281 asFortran << ':';
282 Fortran::semantics::MaybeExpr upper =
283 Fortran::evaluate::AsGenericExpr(triplet->upper());
284
285 if (upper) {
286 uval = Fortran::evaluate::ToInt64(*upper);
287 if (uval) {
288 if (defaultLb) {
289 ubound = builder.createIntegerConstant(loc, idxTy, *uval - 1);
290 } else {
291 mlir::Value ub = builder.createIntegerConstant(loc, idxTy, *uval);
292 ubound = mlir::arith::SubIOp::create(builder, loc, ub, baseLb);
293 }
294 asFortran << *uval;
295 } else {
296 mlir::Value ub =
297 fir::getBase(converter.genExprValue(loc, *upper, stmtCtx));
298 ub = builder.createConvert(loc, baseLb.getType(), ub);
299 ubound = mlir::arith::SubIOp::create(builder, loc, ub, baseLb);
300 asFortran << detail::peelOuterConvert(*upper).AsFortran();
301 }
302 }
303 if (lower && upper) {
304 if (lval && uval && *uval < *lval) {
305 mlir::emitError(loc, "zero sized array section");
306 break;
307 } else {
308 // Stride is mandatory in evaluate::Triplet. Make sure it's 1.
309 auto val = Fortran::evaluate::ToInt64(triplet->GetStride());
310 if (!val || *val != 1) {
311 mlir::emitError(loc, "stride cannot be specified on "
312 "an array section");
313 break;
314 }
315 }
316 }
317
318 extent = genSourceExtent();
319
320 if (dataExvIsAssumedSize && dimension + 1 == dataExvRank) {
321 extent = zero;
322 if (ubound && lbound) {
323 mlir::Value diff =
324 mlir::arith::SubIOp::create(builder, loc, ubound, lbound);
325 extent = mlir::arith::AddIOp::create(builder, loc, diff, one);
326 }
327 if (!ubound)
328 ubound = lbound;
329 }
330
331 if (!ubound) {
332 // ub = extent - 1
333 ubound = mlir::arith::SubIOp::create(builder, loc, extent, one);
334 }
335 }
336
337 // When the strideInBytes is true, it means the stride is from descriptor
338 // and this already includes the lower extents.
339 if (strideIncludeLowerExtent && !strideInBytes) {
340 stride = cumulativeExtent;
341 mlir::Value strideExtent = extent;
342 if (!triplet && dimension + 1 < dataExvRank)
343 strideExtent = genSourceExtent();
344 cumulativeExtent = builder.createOrFold<mlir::arith::MulIOp>(
345 loc, cumulativeExtent, strideExtent);
346 }
347
348 mlir::Value bound =
349 BoundsOp::create(builder, loc, boundTy, lbound, ubound, extent,
350 stride, strideInBytes, baseLb);
351 bounds.push_back(bound);
352 ++dimension;
353 }
354 }
355 return bounds;
356}
357
358namespace detail {
359template <typename Ref, typename Expr> //
360std::optional<Ref> getRef(Expr &&expr) {
361 if constexpr (std::is_same_v<llvm::remove_cvref_t<Expr>,
363 if (auto *ref = std::get_if<Ref>(&expr.u))
364 return *ref;
365 return std::nullopt;
366 } else {
367 auto maybeRef = Fortran::evaluate::ExtractDataRef(expr);
368 if (!maybeRef || !std::holds_alternative<Ref>(maybeRef->u))
369 return std::nullopt;
370 return std::get<Ref>(maybeRef->u);
371 }
372}
373} // namespace detail
374
375template <typename BoundsOp, typename BoundsType>
376fir::factory::AddrAndBoundsInfo gatherDataOperandAddrAndBounds(
377 Fortran::lower::AbstractConverter &converter, fir::FirOpBuilder &builder,
378 semantics::SemanticsContext &semaCtx,
379 Fortran::lower::StatementContext &stmtCtx,
380 Fortran::semantics::SymbolRef symbol,
381 const Fortran::semantics::MaybeExpr &maybeDesignator,
382 mlir::Location operandLocation, std::stringstream &asFortran,
383 llvm::SmallVector<mlir::Value> &bounds, bool treatIndexAsSection = false,
384 bool unwrapFirBox = true, bool genDefaultBounds = true,
385 bool strideIncludeLowerExtent = false,
386 bool loadAllocatableAndPointerComponent = true) {
387 using namespace Fortran;
388
389 fir::factory::AddrAndBoundsInfo info;
390
391 if (!maybeDesignator) {
392 info = getDataOperandBaseAddr(converter, builder, symbol, operandLocation,
393 unwrapFirBox);
394 asFortran << symbol->name().ToString();
395 return info;
396 }
397
398 semantics::SomeExpr designator = *maybeDesignator;
399
400 if ((designator.Rank() > 0 || treatIndexAsSection) &&
401 IsArrayElement(designator)) {
402 auto arrayRef = detail::getRef<evaluate::ArrayRef>(designator);
403 // This shouldn't fail after IsArrayElement(designator).
404 assert(arrayRef && "Expecting ArrayRef");
405
406 fir::ExtendedValue dataExv;
407 bool dataExvIsAssumedSize = false;
408
409 auto toMaybeExpr = [&](auto &&base) {
410 using BaseType = llvm::remove_cvref_t<decltype(base)>;
411 evaluate::ExpressionAnalyzer ea{semaCtx};
412
413 if constexpr (std::is_same_v<evaluate::NamedEntity, BaseType>) {
414 if (auto *ref = base.UnwrapSymbolRef())
415 return ea.Designate(evaluate::DataRef{*ref});
416 if (auto *ref = base.UnwrapComponent())
417 return ea.Designate(evaluate::DataRef{*ref});
418 llvm_unreachable("Unexpected NamedEntity");
419 } else {
420 static_assert(std::is_same_v<semantics::SymbolRef, BaseType>);
421 return ea.Designate(evaluate::DataRef{base});
422 }
423 };
424
425 auto arrayBase = toMaybeExpr(arrayRef->base());
426 assert(arrayBase);
427
428 if (auto comp = detail::getRef<evaluate::Component>(*arrayBase)) {
429 if (!loadAllocatableAndPointerComponent &&
430 semantics::IsAllocatableOrPointer(comp->symbol()))
431 dataExv = converter.genExprMutableBox(operandLocation, *arrayBase);
432 else
433 dataExv = converter.genExprAddr(operandLocation, *arrayBase, stmtCtx);
434 info.addr = fir::getBase(dataExv);
435 info.rawInput = info.addr;
436 asFortran << arrayBase->AsFortran();
437 } else {
438 const semantics::Symbol &sym = arrayRef->GetLastSymbol();
439 dataExvIsAssumedSize =
440 Fortran::semantics::IsAssumedSizeArray(sym.GetUltimate());
441 info = getDataOperandBaseAddr(converter, builder, sym, operandLocation,
442 unwrapFirBox);
443 dataExv = converter.getSymbolExtendedValue(sym);
444 asFortran << sym.name().ToString();
445 }
446
447 if (!arrayRef->subscript().empty()) {
448 asFortran << '(';
450 builder, operandLocation, converter, stmtCtx, arrayRef->subscript(),
451 asFortran, dataExv, dataExvIsAssumedSize, info, treatIndexAsSection,
452 strideIncludeLowerExtent);
453 }
454 asFortran << ')';
455 } else if (auto compRef = detail::getRef<evaluate::Component>(designator)) {
456 fir::ExtendedValue compExv;
457 if (!loadAllocatableAndPointerComponent &&
458 semantics::IsAllocatableOrPointer(compRef->symbol()))
459 compExv = converter.genExprMutableBox(operandLocation, designator);
460 else
461 compExv = converter.genExprAddr(operandLocation, designator, stmtCtx);
462 info.addr = fir::getBase(compExv);
463 info.rawInput = info.addr;
464 if (genDefaultBounds &&
465 mlir::isa<fir::SequenceType>(fir::unwrapRefType(info.addr.getType())))
467 builder, operandLocation, compExv,
468 /*isAssumedSize=*/false, strideIncludeLowerExtent);
469 asFortran << designator.AsFortran();
470
471 if (semantics::IsOptional(compRef->GetLastSymbol())) {
472 info.isPresent = fir::IsPresentOp::create(
473 builder, operandLocation, builder.getI1Type(), info.rawInput);
474 }
475
476 if (unwrapFirBox) {
477 if (auto loadOp =
478 mlir::dyn_cast_or_null<fir::LoadOp>(info.addr.getDefiningOp())) {
479 if (fir::isAllocatableType(loadOp.getType()) ||
480 fir::isPointerType(loadOp.getType())) {
481 info.boxType = info.addr.getType();
482 info.addr =
483 fir::BoxAddrOp::create(builder, operandLocation, info.addr);
484 }
485 info.rawInput = info.addr;
486 }
487 }
488
489 // If the component is an allocatable or pointer the result of
490 // genExprAddr will be the result of a fir.box_addr operation or
491 // a fir.box_addr has been inserted just before.
492 // Retrieve the box so we handle it like other descriptor.
493 if (auto boxAddrOp =
494 mlir::dyn_cast_or_null<fir::BoxAddrOp>(info.addr.getDefiningOp())) {
495 info.addr = boxAddrOp.getVal();
496 info.boxType = info.addr.getType();
497 info.rawInput = info.addr;
498 if (genDefaultBounds)
500 builder, operandLocation, compExv, info);
501 }
502 } else {
503 if (detail::getRef<evaluate::ArrayRef>(designator)) {
504 fir::ExtendedValue compExv =
505 converter.genExprAddr(operandLocation, designator, stmtCtx);
506 info.addr = fir::getBase(compExv);
507 info.rawInput = info.addr;
508 asFortran << designator.AsFortran();
509 } else if (auto symRef = detail::getRef<semantics::SymbolRef>(designator)) {
510 // Scalar or full array.
511 fir::ExtendedValue dataExv = converter.getSymbolExtendedValue(*symRef);
512 info = getDataOperandBaseAddr(converter, builder, *symRef,
513 operandLocation, unwrapFirBox);
514 if (genDefaultBounds && mlir::isa<fir::BaseBoxType>(
515 fir::unwrapRefType(info.addr.getType()))) {
516 info.boxType = fir::unwrapRefType(info.addr.getType());
518 builder, operandLocation, dataExv, info);
519 }
520 bool dataExvIsAssumedSize =
521 Fortran::semantics::IsAssumedSizeArray(symRef->get().GetUltimate());
522 if (genDefaultBounds && mlir::isa<fir::SequenceType>(
523 fir::unwrapRefType(info.addr.getType()))) {
525 builder, operandLocation, dataExv, dataExvIsAssumedSize,
526 strideIncludeLowerExtent);
527 }
528 if ((genDefaultBounds && fir::characterWithDynamicLen(
529 fir::unwrapRefType(info.addr.getType()))) ||
530 mlir::isa<fir::BoxCharType>(
531 fir::unwrapRefType(info.addr.getType()))) {
532 bounds = {fir::factory::genBoundsOpFromBoxChar<BoundsOp, BoundsType>(
533 builder, operandLocation, dataExv, info)};
534 }
535 asFortran << symRef->get().name().ToString();
536 } else { // Unsupported
537 llvm::report_fatal_error("Unsupported type of OpenACC operand");
538 }
539 }
540
541 return info;
542}
543
544} // namespace lower
545} // namespace Fortran
546
547#endif // FORTRAN_LOWER_DIRECTIVES_COMMON_H
Definition common.h:215
Definition type.h:56
Definition AbstractConverter.h:87
virtual fir::MutableBoxValue genExprMutableBox(mlir::Location loc, const SomeExpr &expr)=0
virtual mlir::Value getSymbolAddress(SymbolRef sym)=0
Get the mlir instance of a symbol.
virtual fir::ExtendedValue genExprValue(const SomeExpr &expr, StatementContext &context, mlir::Location *locPtr=nullptr)=0
Generate the computations of the expression to produce a value.
virtual fir::ExtendedValue genExprAddr(const SomeExpr &expr, StatementContext &context, mlir::Location *locPtr=nullptr)=0
Definition StatementContext.h:46
Definition BoxValue.h:475
Definition FIRBuilder.h:59
mlir::Value createConvert(mlir::Location loc, mlir::Type toTy, mlir::Value val)
Lazy creation of fir.convert op.
Definition FIRBuilder.cpp:623
IfBuilder genIfOp(mlir::Location loc, mlir::TypeRange results, mlir::Value cdt, bool withElseRegion)
Definition FIRBuilder.h:550
mlir::Region & getRegion()
Get the current Region of the insertion point.
Definition FIRBuilder.h:113
mlir::Value createIntegerConstant(mlir::Location loc, mlir::Type integerType, std::int64_t i)
Definition FIRBuilder.cpp:148
Definition OpenACC.h:20
Definition ParserActions.h:24
llvm::SmallVector< mlir::Value > genBoundsOps(fir::FirOpBuilder &builder, mlir::Location loc, Fortran::lower::AbstractConverter &converter, Fortran::lower::StatementContext &stmtCtx, const std::vector< Fortran::evaluate::Subscript > &subscripts, std::stringstream &asFortran, fir::ExtendedValue &dataExv, bool dataExvIsAssumedSize, fir::factory::AddrAndBoundsInfo &info, bool treatIndexAsSection=false, bool strideIncludeLowerExtent=false)
Definition DirectivesCommon.h:149
void createEmptyRegionBlocks(fir::FirOpBuilder &builder, std::list< Fortran::lower::pft::Evaluation > &evaluationList)
Definition DirectivesCommon.h:45
Definition bit-population-count.h:20
llvm::SmallVector< mlir::Value > genBaseBoundsOps(fir::FirOpBuilder &builder, mlir::Location loc, fir::ExtendedValue dataExv, bool isAssumedSize, bool strideIncludeLowerExtent=false)
Definition DirectivesCommon.h:276
llvm::SmallVector< mlir::Value > genBoundsOpsFromBox(fir::FirOpBuilder &builder, mlir::Location loc, fir::ExtendedValue dataExv, AddrAndBoundsInfo &info)
Generate the bounds operation from the descriptor information.
Definition DirectivesCommon.h:209
mlir::Value readLowerBound(fir::FirOpBuilder &builder, mlir::Location loc, const fir::ExtendedValue &box, unsigned dim, mlir::Value defaultValue)
Definition FIRBuilder.cpp:1031
mlir::Value readExtent(fir::FirOpBuilder &builder, mlir::Location loc, const fir::ExtendedValue &box, unsigned dim)
Read or get the extent in dimension dim of the array described by box.
Definition FIRBuilder.cpp:1000
bool isBoxAddress(mlir::Type t)
Is t an address to fir.box or class type?
Definition FIRType.h:528
mlir::Value getBase(const ExtendedValue &exv)
Definition BoxValue.cpp:21
bool isPointerType(mlir::Type ty)
Definition FIRType.cpp:315
bool characterWithDynamicLen(mlir::Type t)
Returns true iff t is a fir.char type and has an unknown length.
Definition FIRType.h:256
bool isAllocatableType(mlir::Type ty)
Return true iff ty is the type of an ALLOCATABLE entity or value.
Definition FIRType.cpp:323
Definition expression.h:210
Definition variable.h:288
Definition type.h:399
Definition DirectivesCommon.h:96
Definition PFTBuilder.h:221
Definition DirectivesCommon.h:31