18#ifndef FORTRAN_LOWER_DIRECTIVES_COMMON_H
19#define FORTRAN_LOWER_DIRECTIVES_COMMON_H
21#include "flang/Common/idioms.h"
22#include "flang/Evaluate/tools.h"
23#include "flang/Lower/AbstractConverter.h"
24#include "flang/Lower/Bridge.h"
25#include "flang/Lower/ConvertExpr.h"
26#include "flang/Lower/ConvertVariable.h"
27#include "flang/Lower/OpenACC.h"
28#include "flang/Lower/OpenMP.h"
29#include "flang/Lower/PFTBuilder.h"
30#include "flang/Lower/StatementContext.h"
31#include "flang/Lower/Support/Utils.h"
32#include "flang/Optimizer/Builder/DirectivesCommon.h"
33#include "flang/Optimizer/Builder/HLFIRTools.h"
34#include "flang/Optimizer/Dialect/FIRType.h"
35#include "flang/Parser/parse-tree.h"
36#include "flang/Semantics/openmp-directive-sets.h"
37#include "flang/Semantics/tools.h"
38#include "mlir/Dialect/OpenACC/OpenACC.h"
39#include "mlir/Dialect/OpenMP/OpenMPDialect.h"
40#include "mlir/Dialect/SCF/IR/SCF.h"
41#include "mlir/IR/Value.h"
50template <
typename... TerminatorOps>
53 std::list<Fortran::lower::pft::Evaluation> &evaluationList) {
54 mlir::Region *region = &builder.
getRegion();
57 if (eval.block->empty()) {
59 eval.block = builder.createBlock(region);
61 [[maybe_unused]] mlir::Operation &terminatorOp = eval.block->back();
62 assert(mlir::isa<TerminatorOps...>(terminatorOp) &&
63 "expected terminator op");
66 if (!eval.isDirective() && eval.hasNestedEvaluations())
68 eval.getNestedEvaluations());
75 Fortran::lower::SymbolRef sym, mlir::Location loc,
76 bool unwrapFirBox =
true) {
77 return fir::factory::getDataOperandBaseAddr(
79 Fortran::semantics::IsOptional(sym), loc, unwrapFirBox);
84static T &&AsRvalueRef(T &&t) {
88static T AsRvalueRef(T &t) {
92static T AsRvalueRef(
const T &t) {
103 template <Fortran::common::TypeCategory Category,
int Kind>
104 static Fortran::semantics::MaybeExpr visit_with_category(
107 return Fortran::common::visit(
108 [](
auto &&s) {
return visit_with_category<Category, Kind>(s); },
111 template <Fortran::common::TypeCategory Category,
int Kind>
112 static Fortran::semantics::MaybeExpr visit_with_category(
115 return AsGenericExpr(AsRvalueRef(expr.left()));
117 template <Fortran::common::TypeCategory Category,
int Kind,
typename T>
118 static Fortran::semantics::MaybeExpr visit_with_category(
const T &) {
121 template <Fortran::common::TypeCategory Category,
typename T>
122 static Fortran::semantics::MaybeExpr visit_with_category(
const T &) {
126 template <Fortran::common::TypeCategory Category>
127 static Fortran::semantics::MaybeExpr
130 return Fortran::common::visit(
131 [](
auto &&s) {
return visit_with_category<Category>(s); }, expr.u);
133 static Fortran::semantics::MaybeExpr
135 return Fortran::common::visit([](
auto &&s) {
return visit(s); }, expr.u);
137 template <
typename T>
138 static Fortran::semantics::MaybeExpr visit(
const T &) {
143static inline Fortran::semantics::SomeExpr
144peelOuterConvert(Fortran::semantics::SomeExpr &expr) {
145 if (
auto peeled = PeelConvert::visit(expr))
153template <
typename BoundsOp,
typename BoundsType>
158 const std::vector<Fortran::evaluate::Subscript> &subscripts,
161 bool treatIndexAsSection =
false,
162 bool strideIncludeLowerExtent =
false) {
164 mlir::Type idxTy = builder.getIndexType();
165 mlir::Type boundTy = builder.getType<BoundsType>();
170 const int dataExvRank =
static_cast<int>(dataExv.rank());
171 mlir::Value cumulativeExtent = one;
172 for (
const auto &subscript : subscripts) {
173 const auto *triplet{std::get_if<Fortran::evaluate::Triplet>(&subscript.u)};
174 if (triplet || treatIndexAsSection) {
177 mlir::Value lbound, ubound, extent;
178 std::optional<std::int64_t> lval, uval;
181 bool defaultLb = baseLb == one;
182 mlir::Value stride = one;
183 bool strideInBytes =
false;
185 if (mlir::isa<fir::BaseBoxType>(
186 fir::unwrapRefType(info.addr.getType()))) {
187 if (info.isPresent) {
190 .
genIfOp(loc, idxTy, info.isPresent,
true)
195 : fir::LoadOp::create(builder, loc, info.addr);
198 auto dimInfo = fir::BoxDimsOp::create(builder, loc, idxTy,
199 idxTy, idxTy, box, d);
200 fir::ResultOp::create(builder, loc,
201 dimInfo.getByteStride());
206 fir::ResultOp::create(builder, loc, zero);
212 : fir::LoadOp::create(builder, loc, info.addr);
215 fir::BoxDimsOp::create(builder, loc, idxTy, idxTy, idxTy, box, d);
216 stride = dimInfo.getByteStride();
218 strideInBytes =
true;
221 Fortran::semantics::MaybeExpr
lower;
223 lower = Fortran::evaluate::AsGenericExpr(triplet->lower());
226 using IndirectSubscriptIntegerExpr =
227 Fortran::evaluate::IndirectSubscriptIntegerExpr;
228 using SubscriptInteger = Fortran::evaluate::SubscriptInteger;
230 std::get<IndirectSubscriptIntegerExpr>(subscript.u).value();
231 lower = Fortran::evaluate::AsGenericExpr(std::move(oneInt));
232 if (
lower->Rank() > 0) {
234 loc,
"vector subscript cannot be used for an array section");
239 lval = Fortran::evaluate::ToInt64(*
lower);
245 lbound = mlir::arith::SubIOp::create(builder, loc, lb, baseLb);
252 lbound = mlir::arith::SubIOp::create(builder, loc, lb, baseLb);
253 asFortran << detail::peelOuterConvert(*lower).AsFortran();
269 Fortran::semantics::MaybeExpr upper =
270 Fortran::evaluate::AsGenericExpr(triplet->upper());
273 uval = Fortran::evaluate::ToInt64(*upper);
279 ubound = mlir::arith::SubIOp::create(builder, loc, ub, baseLb);
286 ubound = mlir::arith::SubIOp::create(builder, loc, ub, baseLb);
287 asFortran << detail::peelOuterConvert(*upper).AsFortran();
290 if (
lower && upper) {
291 if (lval && uval && *uval < *lval) {
292 mlir::emitError(loc,
"zero sized array section");
296 auto val = Fortran::evaluate::ToInt64(triplet->GetStride());
297 if (!val || *val != 1) {
298 mlir::emitError(loc,
"stride cannot be specified on "
305 if (info.isPresent && mlir::isa<fir::BaseBoxType>(
306 fir::unwrapRefType(info.addr.getType()))) {
309 .
genIfOp(loc, idxTy, info.isPresent,
true)
312 builder, loc, dataExv, dimension);
313 fir::ResultOp::create(builder, loc, ext);
318 fir::ResultOp::create(builder, loc, zero);
325 if (dataExvIsAssumedSize && dimension + 1 == dataExvRank) {
327 if (ubound && lbound) {
329 mlir::arith::SubIOp::create(builder, loc, ubound, lbound);
330 extent = mlir::arith::AddIOp::create(builder, loc, diff, one);
338 ubound = mlir::arith::SubIOp::create(builder, loc, extent, one);
344 if (strideIncludeLowerExtent && !strideInBytes) {
345 stride = cumulativeExtent;
346 cumulativeExtent = builder.createOrFold<mlir::arith::MulIOp>(
347 loc, cumulativeExtent, extent);
351 BoundsOp::create(builder, loc, boundTy, lbound, ubound, extent,
352 stride, strideInBytes, baseLb);
353 bounds.push_back(bound);
361template <
typename Ref,
typename Expr>
362std::optional<Ref> getRef(Expr &&expr) {
363 if constexpr (std::is_same_v<llvm::remove_cvref_t<Expr>,
365 if (
auto *ref = std::get_if<Ref>(&expr.u))
369 auto maybeRef = Fortran::evaluate::ExtractDataRef(expr);
370 if (!maybeRef || !std::holds_alternative<Ref>(maybeRef->u))
372 return std::get<Ref>(maybeRef->u);
377template <
typename BoundsOp,
typename BoundsType>
378fir::factory::AddrAndBoundsInfo gatherDataOperandAddrAndBounds(
379 Fortran::lower::AbstractConverter &converter, fir::FirOpBuilder &builder,
380 semantics::SemanticsContext &semaCtx,
381 Fortran::lower::StatementContext &stmtCtx,
382 Fortran::semantics::SymbolRef symbol,
383 const Fortran::semantics::MaybeExpr &maybeDesignator,
384 mlir::Location operandLocation, std::stringstream &asFortran,
385 llvm::SmallVector<mlir::Value> &bounds,
bool treatIndexAsSection =
false,
386 bool unwrapFirBox =
true,
bool genDefaultBounds =
true,
387 bool strideIncludeLowerExtent =
false) {
388 using namespace Fortran;
390 fir::factory::AddrAndBoundsInfo info;
392 if (!maybeDesignator) {
393 info = getDataOperandBaseAddr(converter, builder, symbol, operandLocation,
395 asFortran << symbol->name().ToString();
399 semantics::SomeExpr designator = *maybeDesignator;
401 if ((designator.Rank() > 0 || treatIndexAsSection) &&
402 IsArrayElement(designator)) {
403 auto arrayRef = detail::getRef<evaluate::ArrayRef>(designator);
405 assert(arrayRef &&
"Expecting ArrayRef");
407 fir::ExtendedValue dataExv;
408 bool dataExvIsAssumedSize =
false;
410 auto toMaybeExpr = [&](
auto &&base) {
411 using BaseType = llvm::remove_cvref_t<
decltype(base)>;
412 evaluate::ExpressionAnalyzer ea{semaCtx};
414 if constexpr (std::is_same_v<evaluate::NamedEntity, BaseType>) {
415 if (
auto *ref = base.UnwrapSymbolRef())
416 return ea.Designate(evaluate::DataRef{*ref});
417 if (
auto *ref = base.UnwrapComponent())
418 return ea.Designate(evaluate::DataRef{*ref});
419 llvm_unreachable(
"Unexpected NamedEntity");
421 static_assert(std::is_same_v<semantics::SymbolRef, BaseType>);
422 return ea.Designate(evaluate::DataRef{base});
426 auto arrayBase = toMaybeExpr(arrayRef->base());
429 if (detail::getRef<evaluate::Component>(*arrayBase)) {
430 dataExv = converter.
genExprAddr(operandLocation, *arrayBase, stmtCtx);
432 info.rawInput = info.addr;
433 asFortran << arrayBase->AsFortran();
435 const semantics::Symbol &sym = arrayRef->GetLastSymbol();
436 dataExvIsAssumedSize =
437 Fortran::semantics::IsAssumedSizeArray(sym.GetUltimate());
438 info = getDataOperandBaseAddr(converter, builder, sym, operandLocation,
440 dataExv = converter.getSymbolExtendedValue(sym);
441 asFortran << sym.name().ToString();
444 if (!arrayRef->subscript().empty()) {
447 builder, operandLocation, converter, stmtCtx, arrayRef->subscript(),
448 asFortran, dataExv, dataExvIsAssumedSize, info, treatIndexAsSection,
449 strideIncludeLowerExtent);
452 }
else if (
auto compRef = detail::getRef<evaluate::Component>(designator)) {
453 fir::ExtendedValue compExv =
454 converter.
genExprAddr(operandLocation, designator, stmtCtx);
456 info.rawInput = info.addr;
457 if (genDefaultBounds &&
458 mlir::isa<fir::SequenceType>(fir::unwrapRefType(info.addr.getType())))
460 builder, operandLocation, compExv,
461 false, strideIncludeLowerExtent);
462 asFortran << designator.AsFortran();
464 if (semantics::IsOptional(compRef->GetLastSymbol())) {
465 info.isPresent = fir::IsPresentOp::create(
466 builder, operandLocation, builder.getI1Type(), info.rawInput);
471 mlir::dyn_cast_or_null<fir::LoadOp>(info.addr.getDefiningOp())) {
474 info.boxType = info.addr.getType();
476 fir::BoxAddrOp::create(builder, operandLocation, info.addr);
478 info.rawInput = info.addr;
487 mlir::dyn_cast_or_null<fir::BoxAddrOp>(info.addr.getDefiningOp())) {
488 info.addr = boxAddrOp.getVal();
489 info.boxType = info.addr.getType();
490 info.rawInput = info.addr;
491 if (genDefaultBounds)
493 builder, operandLocation, compExv, info);
496 if (detail::getRef<evaluate::ArrayRef>(designator)) {
497 fir::ExtendedValue compExv =
498 converter.
genExprAddr(operandLocation, designator, stmtCtx);
500 info.rawInput = info.addr;
501 asFortran << designator.AsFortran();
502 }
else if (
auto symRef = detail::getRef<semantics::SymbolRef>(designator)) {
504 fir::ExtendedValue dataExv = converter.getSymbolExtendedValue(*symRef);
505 info = getDataOperandBaseAddr(converter, builder, *symRef,
506 operandLocation, unwrapFirBox);
507 if (genDefaultBounds && mlir::isa<fir::BaseBoxType>(
508 fir::unwrapRefType(info.addr.getType()))) {
509 info.boxType = fir::unwrapRefType(info.addr.getType());
511 builder, operandLocation, dataExv, info);
513 bool dataExvIsAssumedSize =
514 Fortran::semantics::IsAssumedSizeArray(symRef->get().GetUltimate());
515 if (genDefaultBounds &&
516 mlir::isa<fir::SequenceType>(fir::unwrapRefType(info.addr.getType())))
518 builder, operandLocation, dataExv, dataExvIsAssumedSize,
519 strideIncludeLowerExtent);
520 asFortran << symRef->get().name().ToString();
522 llvm::report_fatal_error(
"Unsupported type of OpenACC operand");
Definition AbstractConverter.h:85
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:478
Definition FIRBuilder.h:55
mlir::Value createConvert(mlir::Location loc, mlir::Type toTy, mlir::Value val)
Lazy creation of fir.convert op.
Definition FIRBuilder.cpp:611
IfBuilder genIfOp(mlir::Location loc, mlir::TypeRange results, mlir::Value cdt, bool withElseRegion)
Definition FIRBuilder.h:538
mlir::Region & getRegion()
Get the current Region of the insertion point.
Definition FIRBuilder.h:109
mlir::Value createIntegerConstant(mlir::Location loc, mlir::Type integerType, std::int64_t i)
Definition FIRBuilder.cpp:144
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:155
void createEmptyRegionBlocks(fir::FirOpBuilder &builder, std::list< Fortran::lower::pft::Evaluation > &evaluationList)
Definition DirectivesCommon.h:51
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:278
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:211
mlir::Value readLowerBound(fir::FirOpBuilder &builder, mlir::Location loc, const fir::ExtendedValue &box, unsigned dim, mlir::Value defaultValue)
Definition FIRBuilder.cpp:1008
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:977
bool isBoxAddress(mlir::Type t)
Is t an address to fir.box or class type?
Definition FIRType.h:512
mlir::Value getBase(const ExtendedValue &exv)
Definition BoxValue.cpp:21
bool isPointerType(mlir::Type ty)
Definition FIRType.cpp:305
bool isAllocatableType(mlir::Type ty)
Return true iff ty is the type of an ALLOCATABLE entity or value.
Definition FIRType.cpp:313
Definition expression.h:211
Definition variable.h:284
Definition DirectivesCommon.h:102
Definition PFTBuilder.h:221
Definition DirectivesCommon.h:33