18#ifndef FORTRAN_LOWER_DIRECTIVES_COMMON_H
19#define FORTRAN_LOWER_DIRECTIVES_COMMON_H
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"
44template <
typename... TerminatorOps>
47 std::list<Fortran::lower::pft::Evaluation> &evaluationList) {
48 mlir::Region *region = &builder.
getRegion();
51 if (eval.block->empty()) {
53 eval.block = builder.createBlock(region);
55 [[maybe_unused]] mlir::Operation &terminatorOp = eval.block->back();
56 assert(mlir::isa<TerminatorOps...>(terminatorOp) &&
57 "expected terminator op");
60 if (!eval.isDirective() && eval.hasNestedEvaluations())
62 eval.getNestedEvaluations());
69 Fortran::lower::SymbolRef sym, mlir::Location loc,
70 bool unwrapFirBox =
true) {
71 return fir::factory::getDataOperandBaseAddr(
73 Fortran::semantics::IsOptional(sym), loc, unwrapFirBox);
78T &&AsRvalueRef(T &&t) {
86T AsRvalueRef(
const T &t) {
97 template <Fortran::common::TypeCategory Category>
98 static Fortran::semantics::MaybeExpr visit_with_category(
100 return Fortran::common::visit(
101 [](
auto &&s) {
return visit_with_category<Category>(s); }, expr.u);
103 template <Fortran::common::TypeCategory Category,
typename T>
104 static Fortran::semantics::MaybeExpr visit_with_category(
const T &x) {
106 if constexpr (Fortran::evaluate::IsSpecificIntrinsicType<Ty>) {
110 if constexpr (std::is_same_v<T,
112 return AsGenericExpr(AsRvalueRef(x.left()));
118 template <Fortran::common::TypeCategory Category>
119 static Fortran::semantics::MaybeExpr
122 return Fortran::common::visit(
123 [](
auto &&s) {
return visit_with_category<Category>(s); }, expr.u);
125 static Fortran::semantics::MaybeExpr
127 return Fortran::common::visit([](
auto &&s) {
return visit(s); }, expr.u);
129 template <
typename T>
130 static Fortran::semantics::MaybeExpr visit(
const T &) {
135static inline Fortran::semantics::SomeExpr
136peelOuterConvert(Fortran::semantics::SomeExpr &expr) {
137 if (
auto peeled = PeelConvert::visit(expr))
145template <
typename BoundsOp,
typename BoundsType>
150 const std::vector<Fortran::evaluate::Subscript> &subscripts,
153 bool treatIndexAsSection =
false,
154 bool strideIncludeLowerExtent =
false) {
156 mlir::Type idxTy = builder.getIndexType();
157 mlir::Type boundTy = builder.getType<BoundsType>();
162 const int dataExvRank =
static_cast<int>(dataExv.rank());
163 mlir::Value cumulativeExtent = one;
164 for (
const auto &subscript : subscripts) {
165 const auto *triplet{std::get_if<Fortran::evaluate::Triplet>(&subscript.u)};
166 if (triplet || treatIndexAsSection) {
169 mlir::Value lbound, ubound, extent;
170 std::optional<std::int64_t> lval, uval;
173 bool defaultLb = baseLb == one;
174 mlir::Value stride = one;
175 bool strideInBytes =
false;
177 auto genSourceExtent = [&]() -> mlir::Value {
178 if (info.isPresent && mlir::isa<fir::BaseBoxType>(
179 fir::unwrapRefType(info.addr.getType()))) {
181 .
genIfOp(loc, idxTy, info.isPresent,
true)
185 fir::ResultOp::create(builder, loc, ext);
189 fir::ResultOp::create(builder, loc, zero);
196 if (mlir::isa<fir::BaseBoxType>(
197 fir::unwrapRefType(info.addr.getType()))) {
198 if (info.isPresent) {
201 .
genIfOp(loc, idxTy, info.isPresent,
true)
206 : fir::LoadOp::create(builder, loc, info.addr);
209 auto dimInfo = fir::BoxDimsOp::create(builder, loc, idxTy,
210 idxTy, idxTy, box, d);
211 fir::ResultOp::create(builder, loc,
212 dimInfo.getByteStride());
217 fir::ResultOp::create(builder, loc, zero);
223 : fir::LoadOp::create(builder, loc, info.addr);
226 fir::BoxDimsOp::create(builder, loc, idxTy, idxTy, idxTy, box, d);
227 stride = dimInfo.getByteStride();
229 strideInBytes =
true;
232 Fortran::semantics::MaybeExpr
lower;
234 lower = Fortran::evaluate::AsGenericExpr(triplet->lower());
237 using IndirectSubscriptIntegerExpr =
238 Fortran::evaluate::IndirectSubscriptIntegerExpr;
239 using SubscriptInteger = Fortran::evaluate::SubscriptInteger;
241 std::get<IndirectSubscriptIntegerExpr>(subscript.u).value();
242 lower = Fortran::evaluate::AsGenericExpr(std::move(oneInt));
243 if (
lower->Rank() > 0) {
245 loc,
"vector subscript cannot be used for an array section");
250 lval = Fortran::evaluate::ToInt64(*
lower);
256 lbound = mlir::arith::SubIOp::create(builder, loc, lb, baseLb);
263 lbound = mlir::arith::SubIOp::create(builder, loc, lb, baseLb);
264 asFortran << detail::peelOuterConvert(*lower).AsFortran();
280 Fortran::semantics::MaybeExpr upper =
281 Fortran::evaluate::AsGenericExpr(triplet->upper());
284 uval = Fortran::evaluate::ToInt64(*upper);
290 ubound = mlir::arith::SubIOp::create(builder, loc, ub, baseLb);
297 ubound = mlir::arith::SubIOp::create(builder, loc, ub, baseLb);
298 asFortran << detail::peelOuterConvert(*upper).AsFortran();
301 if (
lower && upper) {
302 if (lval && uval && *uval < *lval) {
303 mlir::emitError(loc,
"zero sized array section");
307 auto val = Fortran::evaluate::ToInt64(triplet->GetStride());
308 if (!val || *val != 1) {
309 mlir::emitError(loc,
"stride cannot be specified on "
316 extent = genSourceExtent();
318 if (dataExvIsAssumedSize && dimension + 1 == dataExvRank) {
320 if (ubound && lbound) {
322 mlir::arith::SubIOp::create(builder, loc, ubound, lbound);
323 extent = mlir::arith::AddIOp::create(builder, loc, diff, one);
331 ubound = mlir::arith::SubIOp::create(builder, loc, extent, one);
337 if (strideIncludeLowerExtent && !strideInBytes) {
338 stride = cumulativeExtent;
339 mlir::Value strideExtent = extent;
340 if (!triplet && dimension + 1 < dataExvRank)
341 strideExtent = genSourceExtent();
342 cumulativeExtent = builder.createOrFold<mlir::arith::MulIOp>(
343 loc, cumulativeExtent, strideExtent);
347 BoundsOp::create(builder, loc, boundTy, lbound, ubound, extent,
348 stride, strideInBytes, baseLb);
349 bounds.push_back(bound);
357template <
typename Ref,
typename Expr>
358std::optional<Ref> getRef(Expr &&expr) {
359 if constexpr (std::is_same_v<llvm::remove_cvref_t<Expr>,
361 if (
auto *ref = std::get_if<Ref>(&expr.u))
365 auto maybeRef = Fortran::evaluate::ExtractDataRef(expr);
366 if (!maybeRef || !std::holds_alternative<Ref>(maybeRef->u))
368 return std::get<Ref>(maybeRef->u);
373template <
typename BoundsOp,
typename BoundsType>
374fir::factory::AddrAndBoundsInfo gatherDataOperandAddrAndBounds(
375 Fortran::lower::AbstractConverter &converter, fir::FirOpBuilder &builder,
376 semantics::SemanticsContext &semaCtx,
377 Fortran::lower::StatementContext &stmtCtx,
378 Fortran::semantics::SymbolRef symbol,
379 const Fortran::semantics::MaybeExpr &maybeDesignator,
380 mlir::Location operandLocation, std::stringstream &asFortran,
381 llvm::SmallVector<mlir::Value> &bounds,
bool treatIndexAsSection =
false,
382 bool unwrapFirBox =
true,
bool genDefaultBounds =
true,
383 bool strideIncludeLowerExtent =
false,
384 bool loadAllocatableAndPointerComponent =
true) {
385 using namespace Fortran;
387 fir::factory::AddrAndBoundsInfo info;
389 if (!maybeDesignator) {
390 info = getDataOperandBaseAddr(converter, builder, symbol, operandLocation,
392 asFortran << symbol->name().ToString();
396 semantics::SomeExpr designator = *maybeDesignator;
398 if ((designator.Rank() > 0 || treatIndexAsSection) &&
399 IsArrayElement(designator)) {
400 auto arrayRef = detail::getRef<evaluate::ArrayRef>(designator);
402 assert(arrayRef &&
"Expecting ArrayRef");
404 fir::ExtendedValue dataExv;
405 bool dataExvIsAssumedSize =
false;
407 auto toMaybeExpr = [&](
auto &&base) {
408 using BaseType = llvm::remove_cvref_t<
decltype(base)>;
409 evaluate::ExpressionAnalyzer ea{semaCtx};
411 if constexpr (std::is_same_v<evaluate::NamedEntity, BaseType>) {
412 if (
auto *ref = base.UnwrapSymbolRef())
413 return ea.Designate(evaluate::DataRef{*ref});
414 if (
auto *ref = base.UnwrapComponent())
415 return ea.Designate(evaluate::DataRef{*ref});
416 llvm_unreachable(
"Unexpected NamedEntity");
418 static_assert(std::is_same_v<semantics::SymbolRef, BaseType>);
419 return ea.Designate(evaluate::DataRef{base});
423 auto arrayBase = toMaybeExpr(arrayRef->base());
426 if (
auto comp = detail::getRef<evaluate::Component>(*arrayBase)) {
427 if (!loadAllocatableAndPointerComponent &&
428 semantics::IsAllocatableOrPointer(comp->symbol()))
431 dataExv = converter.
genExprAddr(operandLocation, *arrayBase, stmtCtx);
433 info.rawInput = info.addr;
434 asFortran << arrayBase->AsFortran();
436 const semantics::Symbol &sym = arrayRef->GetLastSymbol();
437 dataExvIsAssumedSize =
438 Fortran::semantics::IsAssumedSizeArray(sym.GetUltimate());
439 info = getDataOperandBaseAddr(converter, builder, sym, operandLocation,
441 dataExv = converter.getSymbolExtendedValue(sym);
442 asFortran << sym.name().ToString();
445 if (!arrayRef->subscript().empty()) {
448 builder, operandLocation, converter, stmtCtx, arrayRef->subscript(),
449 asFortran, dataExv, dataExvIsAssumedSize, info, treatIndexAsSection,
450 strideIncludeLowerExtent);
453 }
else if (
auto compRef = detail::getRef<evaluate::Component>(designator)) {
454 fir::ExtendedValue compExv;
455 if (!loadAllocatableAndPointerComponent &&
456 semantics::IsAllocatableOrPointer(compRef->symbol()))
459 compExv = converter.
genExprAddr(operandLocation, designator, stmtCtx);
461 info.rawInput = info.addr;
462 if (genDefaultBounds &&
463 mlir::isa<fir::SequenceType>(fir::unwrapRefType(info.addr.getType())))
465 builder, operandLocation, compExv,
466 false, strideIncludeLowerExtent);
467 asFortran << designator.AsFortran();
469 if (semantics::IsOptional(compRef->GetLastSymbol())) {
470 info.isPresent = fir::IsPresentOp::create(
471 builder, operandLocation, builder.getI1Type(), info.rawInput);
476 mlir::dyn_cast_or_null<fir::LoadOp>(info.addr.getDefiningOp())) {
479 info.boxType = info.addr.getType();
481 fir::BoxAddrOp::create(builder, operandLocation, info.addr);
483 info.rawInput = info.addr;
492 mlir::dyn_cast_or_null<fir::BoxAddrOp>(info.addr.getDefiningOp())) {
493 info.addr = boxAddrOp.getVal();
494 info.boxType = info.addr.getType();
495 info.rawInput = info.addr;
496 if (genDefaultBounds)
498 builder, operandLocation, compExv, info);
501 if (detail::getRef<evaluate::ArrayRef>(designator)) {
502 fir::ExtendedValue compExv =
503 converter.
genExprAddr(operandLocation, designator, stmtCtx);
505 info.rawInput = info.addr;
506 asFortran << designator.AsFortran();
507 }
else if (
auto symRef = detail::getRef<semantics::SymbolRef>(designator)) {
509 fir::ExtendedValue dataExv = converter.getSymbolExtendedValue(*symRef);
510 info = getDataOperandBaseAddr(converter, builder, *symRef,
511 operandLocation, unwrapFirBox);
512 if (genDefaultBounds && mlir::isa<fir::BaseBoxType>(
513 fir::unwrapRefType(info.addr.getType()))) {
514 info.boxType = fir::unwrapRefType(info.addr.getType());
516 builder, operandLocation, dataExv, info);
518 bool dataExvIsAssumedSize =
519 Fortran::semantics::IsAssumedSizeArray(symRef->get().GetUltimate());
520 if (genDefaultBounds && mlir::isa<fir::SequenceType>(
521 fir::unwrapRefType(info.addr.getType()))) {
523 builder, operandLocation, dataExv, dataExvIsAssumedSize,
524 strideIncludeLowerExtent);
527 fir::unwrapRefType(info.addr.getType()))) ||
528 mlir::isa<fir::BoxCharType>(
529 fir::unwrapRefType(info.addr.getType()))) {
530 bounds = {fir::factory::genBoundsOpFromBoxChar<BoundsOp, BoundsType>(
531 builder, operandLocation, dataExv, info)};
533 asFortran << symRef->get().name().ToString();
535 llvm::report_fatal_error(
"Unsupported type of OpenACC operand");
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, bool allowCoarray=false)=0
Definition StatementContext.h:46
Definition BoxValue.h:469
Definition FIRBuilder.h:66
mlir::Value createConvert(mlir::Location loc, mlir::Type toTy, mlir::Value val)
Lazy creation of fir.convert op.
Definition FIRBuilder.cpp:668
IfBuilder genIfOp(mlir::Location loc, mlir::TypeRange results, mlir::Value cdt, bool withElseRegion)
Definition FIRBuilder.h:589
mlir::Region & getRegion()
Get the current Region of the insertion point.
Definition FIRBuilder.h:120
mlir::Value createIntegerConstant(mlir::Location loc, mlir::Type integerType, std::int64_t i)
Definition FIRBuilder.cpp:150
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:147
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:1078
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:1047
bool isBoxAddress(mlir::Type t)
Is t an address to fir.box or class type?
Definition FIRType.h:535
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:263
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:218
Definition variable.h:293
Definition DirectivesCommon.h:96
Definition PFTBuilder.h:222
Definition DirectivesCommon.h:31