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"
42#include "llvm/Frontend/OpenMP/OMPConstants.h"
51static inline void genOmpAtomicHintAndMemoryOrderClauses(
54 mlir::IntegerAttr &hint,
55 mlir::omp::ClauseMemoryOrderKindAttr &memoryOrder) {
58 if (
const auto *ompClause =
59 std::get_if<Fortran::parser::OmpClause>(&clause.u)) {
60 if (
const auto *hintClause =
61 std::get_if<Fortran::parser::OmpClause::Hint>(&ompClause->u)) {
62 const auto *expr = Fortran::semantics::GetExpr(hintClause->v);
63 uint64_t hintExprValue = *Fortran::evaluate::ToInt64(*expr);
64 hint = firOpBuilder.getI64IntegerAttr(hintExprValue);
66 }
else if (
const auto *ompMemoryOrderClause =
67 std::get_if<Fortran::parser::OmpMemoryOrderClause>(
69 if (std::get_if<Fortran::parser::OmpClause::Acquire>(
70 &ompMemoryOrderClause->v.u)) {
71 memoryOrder = mlir::omp::ClauseMemoryOrderKindAttr::get(
72 firOpBuilder.getContext(),
73 mlir::omp::ClauseMemoryOrderKind::Acquire);
74 }
else if (std::get_if<Fortran::parser::OmpClause::Relaxed>(
75 &ompMemoryOrderClause->v.u)) {
76 memoryOrder = mlir::omp::ClauseMemoryOrderKindAttr::get(
77 firOpBuilder.getContext(),
78 mlir::omp::ClauseMemoryOrderKind::Relaxed);
79 }
else if (std::get_if<Fortran::parser::OmpClause::SeqCst>(
80 &ompMemoryOrderClause->v.u)) {
81 memoryOrder = mlir::omp::ClauseMemoryOrderKindAttr::get(
82 firOpBuilder.getContext(),
83 mlir::omp::ClauseMemoryOrderKind::Seq_cst);
84 }
else if (std::get_if<Fortran::parser::OmpClause::Release>(
85 &ompMemoryOrderClause->v.u)) {
86 memoryOrder = mlir::omp::ClauseMemoryOrderKindAttr::get(
87 firOpBuilder.getContext(),
88 mlir::omp::ClauseMemoryOrderKind::Release);
94template <
typename AtomicListT>
95static void processOmpAtomicTODO(mlir::Type elementType,
96 [[maybe_unused]] mlir::Location loc) {
99 if constexpr (std::is_same<AtomicListT,
102 "is supported type for omp atomic");
108template <
typename AtomicListT>
109static inline void genOmpAccAtomicCaptureStatement(
111 mlir::Value toAddress,
112 [[maybe_unused]]
const AtomicListT *leftHandClauseList,
113 [[maybe_unused]]
const AtomicListT *rightHandClauseList,
114 mlir::Type elementType, mlir::Location loc) {
118 processOmpAtomicTODO<AtomicListT>(elementType, loc);
120 if constexpr (std::is_same<AtomicListT,
124 mlir::IntegerAttr hint =
nullptr;
126 mlir::omp::ClauseMemoryOrderKindAttr memoryOrder =
nullptr;
127 if (leftHandClauseList)
128 genOmpAtomicHintAndMemoryOrderClauses(converter, *leftHandClauseList,
130 if (rightHandClauseList)
131 genOmpAtomicHintAndMemoryOrderClauses(converter, *rightHandClauseList,
133 firOpBuilder.create<mlir::omp::AtomicReadOp>(
134 loc, fromAddress, toAddress, mlir::TypeAttr::get(elementType), hint,
137 firOpBuilder.create<mlir::acc::AtomicReadOp>(
138 loc, fromAddress, toAddress, mlir::TypeAttr::get(elementType));
144template <
typename AtomicListT>
145static inline void genOmpAccAtomicWriteStatement(
147 mlir::Value rhsExpr, [[maybe_unused]]
const AtomicListT *leftHandClauseList,
148 [[maybe_unused]]
const AtomicListT *rightHandClauseList, mlir::Location loc,
149 mlir::Value *evaluatedExprValue =
nullptr) {
153 mlir::Type varType = fir::unwrapRefType(lhsAddr.getType());
155 auto insertionPoint = firOpBuilder.saveInsertionPoint();
156 firOpBuilder.setInsertionPointAfter(rhsExpr.getDefiningOp());
158 firOpBuilder.restoreInsertionPoint(insertionPoint);
160 processOmpAtomicTODO<AtomicListT>(varType, loc);
162 if constexpr (std::is_same<AtomicListT,
166 mlir::IntegerAttr hint =
nullptr;
167 mlir::omp::ClauseMemoryOrderKindAttr memoryOrder =
nullptr;
168 if (leftHandClauseList)
169 genOmpAtomicHintAndMemoryOrderClauses(converter, *leftHandClauseList,
171 if (rightHandClauseList)
172 genOmpAtomicHintAndMemoryOrderClauses(converter, *rightHandClauseList,
174 firOpBuilder.create<mlir::omp::AtomicWriteOp>(loc, lhsAddr, rhsExpr, hint,
177 firOpBuilder.create<mlir::acc::AtomicWriteOp>(loc, lhsAddr, rhsExpr);
183template <
typename AtomicListT>
184static inline void genOmpAccAtomicUpdateStatement(
188 [[maybe_unused]]
const AtomicListT *leftHandClauseList,
189 [[maybe_unused]]
const AtomicListT *rightHandClauseList, mlir::Location loc,
190 mlir::Operation *atomicCaptureOp =
nullptr) {
209 auto getArgExpression =
210 [](std::list<parser::ActualArgSpec>::const_iterator it) {
211 const auto &arg{std::get<parser::ActualArg>((*it).t)};
212 const auto *parserExpr{
213 std::get_if<common::Indirection<parser::Expr>>(&arg.u)};
219 Fortran::lower::ExprToValueMap exprValueOverrides;
223 Fortran::common::visit(
225 [&](
const common::Indirection<parser::FunctionReference> &funcRef)
227 const auto &args{std::get<std::list<parser::ActualArgSpec>>(
228 funcRef.value().v.t)};
229 std::list<parser::ActualArgSpec>::const_iterator beginIt =
231 std::list<parser::ActualArgSpec>::const_iterator endIt = args.end();
232 const auto *exprFirst{getArgExpression(beginIt)};
233 if (exprFirst && exprFirst->value().source ==
234 assignmentStmtVariable.GetSource()) {
241 std::list<parser::ActualArgSpec>::const_iterator it;
242 for (it = beginIt; it != endIt; it++) {
243 const common::Indirection<parser::Expr> *expr =
244 getArgExpression(it);
246 nonAtomicSubExprs.push_back(Fortran::semantics::GetExpr(*expr));
249 [&](
const auto &op) ->
void {
250 using T = std::decay_t<
decltype(op)>;
251 if constexpr (std::is_base_of<
254 const auto &exprLeft{std::get<0>(op.t)};
255 const auto &exprRight{std::get<1>(op.t)};
256 if (exprLeft.value().source == assignmentStmtVariable.GetSource())
257 nonAtomicSubExprs.push_back(
258 Fortran::semantics::GetExpr(exprRight));
260 nonAtomicSubExprs.push_back(
261 Fortran::semantics::GetExpr(exprLeft));
265 assignmentStmtExpr.u);
266 StatementContext nonAtomicStmtCtx;
267 if (!nonAtomicSubExprs.empty()) {
269 auto insertionPoint = firOpBuilder.saveInsertionPoint();
271 firOpBuilder.setInsertionPoint(atomicCaptureOp);
272 mlir::Value nonAtomicVal;
273 for (
auto *nonAtomicSubExpr : nonAtomicSubExprs) {
275 currentLocation, *nonAtomicSubExpr, nonAtomicStmtCtx));
276 exprValueOverrides.try_emplace(nonAtomicSubExpr, nonAtomicVal);
279 firOpBuilder.restoreInsertionPoint(insertionPoint);
282 mlir::Operation *atomicUpdateOp =
nullptr;
283 if constexpr (std::is_same<AtomicListT,
287 mlir::IntegerAttr hint =
nullptr;
288 mlir::omp::ClauseMemoryOrderKindAttr memoryOrder =
nullptr;
289 if (leftHandClauseList)
290 genOmpAtomicHintAndMemoryOrderClauses(converter, *leftHandClauseList,
292 if (rightHandClauseList)
293 genOmpAtomicHintAndMemoryOrderClauses(converter, *rightHandClauseList,
295 atomicUpdateOp = firOpBuilder.create<mlir::omp::AtomicUpdateOp>(
296 currentLocation, lhsAddr, hint, memoryOrder);
298 atomicUpdateOp = firOpBuilder.create<mlir::acc::AtomicUpdateOp>(
299 currentLocation, lhsAddr);
302 processOmpAtomicTODO<AtomicListT>(varType, loc);
306 firOpBuilder.createBlock(&atomicUpdateOp->getRegion(0), {}, varTys, locs);
308 fir::getBase(atomicUpdateOp->getRegion(0).front().getArgument(0));
310 exprValueOverrides.try_emplace(
311 Fortran::semantics::GetExpr(assignmentStmtVariable), val);
317 *Fortran::semantics::GetExpr(assignmentStmtExpr), atomicStmtCtx));
318 mlir::Value convertResult =
319 firOpBuilder.
createConvert(currentLocation, varType, rhsExpr);
320 if constexpr (std::is_same<AtomicListT,
322 firOpBuilder.create<mlir::omp::YieldOp>(currentLocation, convertResult);
324 firOpBuilder.create<mlir::acc::YieldOp>(currentLocation, convertResult);
326 converter.resetExprOverrides();
328 firOpBuilder.setInsertionPointAfter(atomicUpdateOp);
332template <
typename AtomicT,
typename AtomicListT>
334 const AtomicT &atomicWrite, mlir::Location loc) {
335 const AtomicListT *rightHandClauseList =
nullptr;
336 const AtomicListT *leftHandClauseList =
nullptr;
337 if constexpr (std::is_same<AtomicListT,
340 rightHandClauseList = &std::get<2>(atomicWrite.t);
341 leftHandClauseList = &std::get<0>(atomicWrite.t);
345 std::get<Fortran::parser::Statement<Fortran::parser::AssignmentStmt>>(
351 mlir::Value rhsExpr =
353 mlir::Value lhsAddr =
355 genOmpAccAtomicWriteStatement(converter, lhsAddr, rhsExpr, leftHandClauseList,
356 rightHandClauseList, loc);
360template <
typename AtomicT,
typename AtomicListT>
362 const AtomicT &atomicRead, mlir::Location loc) {
363 const AtomicListT *rightHandClauseList =
nullptr;
364 const AtomicListT *leftHandClauseList =
nullptr;
365 if constexpr (std::is_same<AtomicListT,
368 rightHandClauseList = &std::get<2>(atomicRead.t);
369 leftHandClauseList = &std::get<0>(atomicRead.t);
372 const auto &assignmentStmtExpr = std::get<Fortran::parser::Expr>(
376 const auto &assignmentStmtVariable = std::get<Fortran::parser::Variable>(
383 *Fortran::semantics::GetExpr(assignmentStmtExpr);
384 mlir::Type elementType = converter.
genType(fromExpr);
385 mlir::Value fromAddress =
388 *Fortran::semantics::GetExpr(assignmentStmtVariable), stmtCtx));
389 genOmpAccAtomicCaptureStatement(converter, fromAddress, toAddress,
390 leftHandClauseList, rightHandClauseList,
395template <
typename AtomicT,
typename AtomicListT>
397 const AtomicT &atomicUpdate, mlir::Location loc) {
398 const AtomicListT *rightHandClauseList =
nullptr;
399 const AtomicListT *leftHandClauseList =
nullptr;
400 if constexpr (std::is_same<AtomicListT,
403 rightHandClauseList = &std::get<2>(atomicUpdate.t);
404 leftHandClauseList = &std::get<0>(atomicUpdate.t);
407 const auto &assignmentStmtExpr = std::get<Fortran::parser::Expr>(
411 const auto &assignmentStmtVariable = std::get<Fortran::parser::Variable>(
418 *Fortran::semantics::GetExpr(assignmentStmtVariable), stmtCtx));
419 mlir::Type varType = fir::unwrapRefType(lhsAddr.getType());
420 genOmpAccAtomicUpdateStatement<AtomicListT>(
421 converter, lhsAddr, varType, assignmentStmtVariable, assignmentStmtExpr,
422 leftHandClauseList, rightHandClauseList, loc);
426template <
typename AtomicT,
typename AtomicListT>
428 const AtomicT &atomicConstruct, mlir::Location loc) {
429 const AtomicListT &atomicClauseList =
430 std::get<AtomicListT>(atomicConstruct.t);
431 const auto &assignmentStmtExpr = std::get<Fortran::parser::Expr>(
435 const auto &assignmentStmtVariable = std::get<Fortran::parser::Variable>(
441 *Fortran::semantics::GetExpr(assignmentStmtVariable), stmtCtx));
442 mlir::Type varType = fir::unwrapRefType(lhsAddr.getType());
445 genOmpAccAtomicUpdateStatement<AtomicListT>(
446 converter, lhsAddr, varType, assignmentStmtVariable, assignmentStmtExpr,
447 &atomicClauseList,
nullptr, loc);
451template <
typename AtomicT,
typename AtomicListT>
453 const AtomicT &atomicCapture, mlir::Location loc) {
457 std::get<typename AtomicT::Stmt1>(atomicCapture.t).v.statement;
459 const auto &stmt1Var{std::get<Fortran::parser::Variable>(stmt1.t)};
460 const auto &stmt1Expr{std::get<Fortran::parser::Expr>(stmt1.t)};
462 std::get<typename AtomicT::Stmt2>(atomicCapture.t).v.statement;
464 const auto &stmt2Var{std::get<Fortran::parser::Variable>(stmt2.t)};
465 const auto &stmt2Expr{std::get<Fortran::parser::Expr>(stmt2.t)};
473 mlir::Value stmt1LHSArg =
475 mlir::Value stmt2LHSArg =
479 mlir::Type stmt1VarType =
481 mlir::Type stmt2VarType =
484 mlir::Operation *atomicCaptureOp =
nullptr;
485 if constexpr (std::is_same<AtomicListT,
487 mlir::IntegerAttr hint =
nullptr;
488 mlir::omp::ClauseMemoryOrderKindAttr memoryOrder =
nullptr;
489 const AtomicListT &rightHandClauseList = std::get<2>(atomicCapture.t);
490 const AtomicListT &leftHandClauseList = std::get<0>(atomicCapture.t);
491 genOmpAtomicHintAndMemoryOrderClauses(converter, leftHandClauseList, hint,
493 genOmpAtomicHintAndMemoryOrderClauses(converter, rightHandClauseList, hint,
496 firOpBuilder.create<mlir::omp::AtomicCaptureOp>(loc, hint, memoryOrder);
498 atomicCaptureOp = firOpBuilder.create<mlir::acc::AtomicCaptureOp>(loc);
501 firOpBuilder.createBlock(&(atomicCaptureOp->getRegion(0)));
502 mlir::Block &block = atomicCaptureOp->getRegion(0).back();
503 firOpBuilder.setInsertionPointToStart(&block);
504 if (Fortran::semantics::checkForSingleVariableOnRHS(stmt1)) {
505 if (Fortran::semantics::checkForSymbolMatch(stmt2)) {
508 *Fortran::semantics::GetExpr(stmt1Expr);
509 mlir::Type elementType = converter.
genType(fromExpr);
510 genOmpAccAtomicCaptureStatement<AtomicListT>(
511 converter, stmt2LHSArg, stmt1LHSArg,
513 nullptr, elementType, loc);
514 genOmpAccAtomicUpdateStatement<AtomicListT>(
515 converter, stmt2LHSArg, stmt2VarType, stmt2Var, stmt2Expr,
517 nullptr, loc, atomicCaptureOp);
520 firOpBuilder.setInsertionPoint(atomicCaptureOp);
521 mlir::Value stmt2RHSArg =
523 firOpBuilder.setInsertionPointToStart(&block);
525 *Fortran::semantics::GetExpr(stmt1Expr);
526 mlir::Type elementType = converter.
genType(fromExpr);
527 genOmpAccAtomicCaptureStatement<AtomicListT>(
528 converter, stmt2LHSArg, stmt1LHSArg,
530 nullptr, elementType, loc);
531 genOmpAccAtomicWriteStatement<AtomicListT>(
532 converter, stmt2LHSArg, stmt2RHSArg,
539 *Fortran::semantics::GetExpr(stmt2Expr);
540 mlir::Type elementType = converter.
genType(fromExpr);
541 genOmpAccAtomicUpdateStatement<AtomicListT>(
542 converter, stmt1LHSArg, stmt1VarType, stmt1Var, stmt1Expr,
544 nullptr, loc, atomicCaptureOp);
545 genOmpAccAtomicCaptureStatement<AtomicListT>(
546 converter, stmt1LHSArg, stmt2LHSArg,
548 nullptr, elementType, loc);
550 firOpBuilder.setInsertionPointToEnd(&block);
551 if constexpr (std::is_same<AtomicListT,
553 firOpBuilder.create<mlir::omp::TerminatorOp>(loc);
555 firOpBuilder.create<mlir::acc::TerminatorOp>(loc);
557 firOpBuilder.setInsertionPointToStart(&block);
562template <
typename... TerminatorOps>
565 std::list<Fortran::lower::pft::Evaluation> &evaluationList) {
566 mlir::Region *region = &builder.
getRegion();
569 if (eval.block->empty()) {
571 eval.block = builder.createBlock(region);
573 [[maybe_unused]] mlir::Operation &terminatorOp = eval.block->back();
574 assert(mlir::isa<TerminatorOps...>(terminatorOp) &&
575 "expected terminator op");
578 if (!eval.isDirective() && eval.hasNestedEvaluations())
580 eval.getNestedEvaluations());
588 return fir::factory::getDataOperandBaseAddr(
590 Fortran::semantics::IsOptional(sym), loc);
595static T &&AsRvalueRef(T &&t) {
599static T AsRvalueRef(T &t) {
603static T AsRvalueRef(
const T &t) {
614 template <Fortran::common::TypeCategory Category,
int Kind>
615 static Fortran::semantics::MaybeExpr visit_with_category(
618 return Fortran::common::visit(
619 [](
auto &&s) {
return visit_with_category<Category, Kind>(s); },
622 template <Fortran::common::TypeCategory Category,
int Kind>
623 static Fortran::semantics::MaybeExpr visit_with_category(
626 return AsGenericExpr(AsRvalueRef(expr.left()));
628 template <Fortran::common::TypeCategory Category,
int Kind,
typename T>
629 static Fortran::semantics::MaybeExpr visit_with_category(
const T &) {
632 template <Fortran::common::TypeCategory Category,
typename T>
633 static Fortran::semantics::MaybeExpr visit_with_category(
const T &) {
637 template <Fortran::common::TypeCategory Category>
638 static Fortran::semantics::MaybeExpr
641 return Fortran::common::visit(
642 [](
auto &&s) {
return visit_with_category<Category>(s); }, expr.u);
644 static Fortran::semantics::MaybeExpr
646 return Fortran::common::visit([](
auto &&s) {
return visit(s); }, expr.u);
648 template <
typename T>
649 static Fortran::semantics::MaybeExpr visit(
const T &) {
656 if (
auto peeled = PeelConvert::visit(expr))
664template <
typename BoundsOp,
typename BoundsType>
669 const std::vector<Fortran::evaluate::Subscript> &subscripts,
672 bool treatIndexAsSection =
false) {
674 mlir::Type idxTy = builder.getIndexType();
675 mlir::Type boundTy = builder.getType<BoundsType>();
680 const int dataExvRank =
static_cast<int>(dataExv.rank());
681 for (
const auto &subscript : subscripts) {
682 const auto *triplet{std::get_if<Fortran::evaluate::Triplet>(&subscript.u)};
683 if (triplet || treatIndexAsSection) {
686 mlir::Value lbound, ubound, extent;
687 std::optional<std::int64_t> lval, uval;
690 bool defaultLb = baseLb == one;
691 mlir::Value stride = one;
692 bool strideInBytes =
false;
694 if (mlir::isa<fir::BaseBoxType>(
695 fir::unwrapRefType(info.addr.getType()))) {
696 if (info.isPresent) {
699 .
genIfOp(loc, idxTy, info.isPresent,
true)
704 : builder.create<fir::LoadOp>(loc, info.addr);
707 auto dimInfo = builder.create<fir::BoxDimsOp>(
708 loc, idxTy, idxTy, idxTy, box, d);
709 builder.create<fir::ResultOp>(loc, dimInfo.getByteStride());
714 builder.create<fir::ResultOp>(loc, zero);
720 : builder.create<fir::LoadOp>(loc, info.addr);
723 builder.create<fir::BoxDimsOp>(loc, idxTy, idxTy, idxTy, box, d);
724 stride = dimInfo.getByteStride();
726 strideInBytes =
true;
729 Fortran::semantics::MaybeExpr lower;
731 lower = Fortran::evaluate::AsGenericExpr(triplet->lower());
738 std::get<IndirectSubscriptIntegerExpr>(subscript.u).value();
739 lower = Fortran::evaluate::AsGenericExpr(std::move(oneInt));
740 if (lower->Rank() > 0) {
742 loc,
"vector subscript cannot be used for an array section");
747 lval = Fortran::evaluate::ToInt64(*lower);
753 lbound = builder.create<mlir::arith::SubIOp>(loc, lb, baseLb);
760 lbound = builder.create<mlir::arith::SubIOp>(loc, lb, baseLb);
761 asFortran << detail::peelOuterConvert(*lower).AsFortran();
777 Fortran::semantics::MaybeExpr upper =
778 Fortran::evaluate::AsGenericExpr(triplet->upper());
781 uval = Fortran::evaluate::ToInt64(*upper);
787 ubound = builder.create<mlir::arith::SubIOp>(loc, ub, baseLb);
794 ubound = builder.create<mlir::arith::SubIOp>(loc, ub, baseLb);
795 asFortran << detail::peelOuterConvert(*upper).AsFortran();
798 if (lower && upper) {
799 if (lval && uval && *uval < *lval) {
800 mlir::emitError(loc,
"zero sized array section");
804 auto val = Fortran::evaluate::ToInt64(triplet->GetStride());
805 if (!val || *val != 1) {
806 mlir::emitError(loc,
"stride cannot be specified on "
813 if (info.isPresent && mlir::isa<fir::BaseBoxType>(
814 fir::unwrapRefType(info.addr.getType()))) {
817 .
genIfOp(loc, idxTy, info.isPresent,
true)
820 builder, loc, dataExv, dimension);
821 builder.create<fir::ResultOp>(loc, ext);
826 builder.create<fir::ResultOp>(loc, zero);
833 if (dataExvIsAssumedSize && dimension + 1 == dataExvRank) {
835 if (ubound && lbound) {
837 builder.create<mlir::arith::SubIOp>(loc, ubound, lbound);
838 extent = builder.create<mlir::arith::AddIOp>(loc, diff, one);
846 ubound = builder.create<mlir::arith::SubIOp>(loc, extent, one);
849 mlir::Value bound = builder.create<BoundsOp>(
850 loc, boundTy, lbound, ubound, extent, stride, strideInBytes, baseLb);
851 bounds.push_back(bound);
859template <
typename Ref,
typename Expr>
860std::optional<Ref> getRef(Expr &&expr) {
861 if constexpr (std::is_same_v<llvm::remove_cvref_t<Expr>,
863 if (
auto *ref = std::get_if<Ref>(&expr.u))
867 auto maybeRef = Fortran::evaluate::ExtractDataRef(expr);
868 if (!maybeRef || !std::holds_alternative<Ref>(maybeRef->u))
870 return std::get<Ref>(maybeRef->u);
875template <
typename BoundsOp,
typename BoundsType>
878 semantics::SemanticsContext &semaCtx,
881 const Fortran::semantics::MaybeExpr &maybeDesignator,
882 mlir::Location operandLocation, std::stringstream &asFortran,
888 if (!maybeDesignator) {
889 info = getDataOperandBaseAddr(converter, builder, symbol, operandLocation);
890 asFortran << symbol->name().ToString();
896 if ((designator.Rank() > 0 || treatIndexAsSection) &&
897 IsArrayElement(designator)) {
898 auto arrayRef = detail::getRef<evaluate::ArrayRef>(designator);
900 assert(arrayRef &&
"Expecting ArrayRef");
903 bool dataExvIsAssumedSize =
false;
905 auto toMaybeExpr = [&](
auto &&base) {
906 using BaseType = llvm::remove_cvref_t<
decltype(base)>;
909 if constexpr (std::is_same_v<evaluate::NamedEntity, BaseType>) {
910 if (
auto *ref = base.UnwrapSymbolRef())
912 if (
auto *ref = base.UnwrapComponent())
914 llvm_unreachable(
"Unexpected NamedEntity");
916 static_assert(std::is_same_v<semantics::SymbolRef, BaseType>);
921 auto arrayBase = toMaybeExpr(arrayRef->base());
924 if (detail::getRef<evaluate::Component>(*arrayBase)) {
925 dataExv = converter.
genExprAddr(operandLocation, *arrayBase, stmtCtx);
927 info.rawInput = info.addr;
928 asFortran << arrayBase->AsFortran();
931 dataExvIsAssumedSize =
932 Fortran::semantics::IsAssumedSizeArray(sym.GetUltimate());
933 info = getDataOperandBaseAddr(converter, builder, sym, operandLocation);
934 dataExv = converter.getSymbolExtendedValue(sym);
935 asFortran << sym.name().ToString();
938 if (!arrayRef->subscript().empty()) {
940 bounds = genBoundsOps<BoundsOp, BoundsType>(
941 builder, operandLocation, converter, stmtCtx, arrayRef->subscript(),
942 asFortran, dataExv, dataExvIsAssumedSize, info, treatIndexAsSection);
945 }
else if (
auto compRef = detail::getRef<evaluate::Component>(designator)) {
947 converter.
genExprAddr(operandLocation, designator, stmtCtx);
949 info.rawInput = info.addr;
950 if (mlir::isa<fir::SequenceType>(fir::unwrapRefType(info.addr.getType())))
951 bounds = fir::factory::genBaseBoundsOps<BoundsOp, BoundsType>(
952 builder, operandLocation, compExv,
954 asFortran << designator.AsFortran();
956 if (semantics::IsOptional(compRef->GetLastSymbol())) {
957 info.isPresent = builder.create<fir::IsPresentOp>(
958 operandLocation, builder.getI1Type(), info.rawInput);
962 mlir::dyn_cast_or_null<fir::LoadOp>(info.addr.getDefiningOp())) {
965 info.boxType = info.addr.getType();
966 info.addr = builder.create<fir::BoxAddrOp>(operandLocation, info.addr);
968 info.rawInput = info.addr;
976 mlir::dyn_cast_or_null<fir::BoxAddrOp>(info.addr.getDefiningOp())) {
977 info.addr = boxAddrOp.getVal();
978 info.boxType = info.addr.getType();
979 info.rawInput = info.addr;
980 bounds = fir::factory::genBoundsOpsFromBox<BoundsOp, BoundsType>(
981 builder, operandLocation, compExv, info);
984 if (detail::getRef<evaluate::ArrayRef>(designator)) {
986 converter.
genExprAddr(operandLocation, designator, stmtCtx);
988 info.rawInput = info.addr;
989 asFortran << designator.AsFortran();
990 }
else if (
auto symRef = detail::getRef<semantics::SymbolRef>(designator)) {
994 getDataOperandBaseAddr(converter, builder, *symRef, operandLocation);
995 if (mlir::isa<fir::BaseBoxType>(
996 fir::unwrapRefType(info.addr.getType()))) {
997 info.boxType = fir::unwrapRefType(info.addr.getType());
998 bounds = fir::factory::genBoundsOpsFromBox<BoundsOp, BoundsType>(
999 builder, operandLocation, dataExv, info);
1001 bool dataExvIsAssumedSize =
1002 Fortran::semantics::IsAssumedSizeArray(symRef->get().GetUltimate());
1003 if (mlir::isa<fir::SequenceType>(fir::unwrapRefType(info.addr.getType())))
1004 bounds = fir::factory::genBaseBoundsOps<BoundsOp, BoundsType>(
1005 builder, operandLocation, dataExv, dataExvIsAssumedSize);
1006 asFortran << symRef->get().name().ToString();
1008 llvm::report_fatal_error(
"Unsupported type of OpenACC operand");
Definition: indirection.h:72
Definition: expression.h:878
Definition: expression.h:102
Definition: AbstractConverter.h:82
virtual mlir::Value getSymbolAddress(SymbolRef sym)=0
Get the mlir instance of a symbol.
virtual mlir::Location getCurrentLocation()=0
Get the converter's current location.
virtual mlir::Type genType(const SomeExpr &)=0
Generate the type of an Expr.
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 void overrideExprValues(const ExprToValueMap *)=0
virtual fir::FirOpBuilder & getFirOpBuilder()=0
Get the OpBuilder.
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:511
IfBuilder genIfOp(mlir::Location loc, mlir::TypeRange results, mlir::Value cdt, bool withElseRegion)
Definition: FIRBuilder.h:463
mlir::Region & getRegion()
Get the current Region of the insertion point.
Definition: FIRBuilder.h:103
mlir::Value createIntegerConstant(mlir::Location loc, mlir::Type integerType, std::int64_t i)
Definition: FIRBuilder.cpp:131
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)
Definition: DirectivesCommon.h:666
void genOmpAccAtomicRead(Fortran::lower::AbstractConverter &converter, const AtomicT &atomicRead, mlir::Location loc)
Processes an atomic construct with read clause.
Definition: DirectivesCommon.h:361
void genOmpAtomic(Fortran::lower::AbstractConverter &converter, const AtomicT &atomicConstruct, mlir::Location loc)
Processes an atomic construct with no clause - which implies update clause.
Definition: DirectivesCommon.h:427
void genOmpAccAtomicUpdate(Fortran::lower::AbstractConverter &converter, const AtomicT &atomicUpdate, mlir::Location loc)
Processes an atomic construct with update clause.
Definition: DirectivesCommon.h:396
void createEmptyRegionBlocks(fir::FirOpBuilder &builder, std::list< Fortran::lower::pft::Evaluation > &evaluationList)
Definition: DirectivesCommon.h:563
void genOmpAccAtomicWrite(Fortran::lower::AbstractConverter &converter, const AtomicT &atomicWrite, mlir::Location loc)
Processes an atomic construct with write clause.
Definition: DirectivesCommon.h:333
void genOmpAccAtomicCapture(Fortran::lower::AbstractConverter &converter, const AtomicT &atomicCapture, mlir::Location loc)
Processes an atomic construct with capture clause.
Definition: DirectivesCommon.h:452
Definition: bit-population-count.h:20
mlir::Value readLowerBound(fir::FirOpBuilder &builder, mlir::Location loc, const fir::ExtendedValue &box, unsigned dim, mlir::Value defaultValue)
Definition: FIRBuilder.cpp:905
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:873
bool isBoxAddress(mlir::Type t)
Is t an address to fir.box or class type?
Definition: FIRType.h:475
mlir::Value getBase(const ExtendedValue &exv)
Definition: BoxValue.cpp:21
bool isPointerType(mlir::Type ty)
Definition: FIRType.cpp:273
bool isAllocatableType(mlir::Type ty)
Return true iff ty is the type of an ALLOCATABLE entity or value.
Definition: FIRType.cpp:281
bool isa_trivial(mlir::Type t)
Definition: FIRType.h:202
Definition: expression.h:211
Definition: variable.h:300
Definition: DirectivesCommon.h:613
Definition: PFTBuilder.h:216
Definition: parse-tree.h:2016
Definition: parse-tree.h:1724
Definition: parse-tree.h:1700
Definition: parse-tree.h:4568
Definition: parse-tree.h:4561
Definition: parse-tree.h:355
Definition: parse-tree.h:1865
Definition: DirectivesCommon.h:31