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/BoxValue.h"
33#include "flang/Optimizer/Builder/FIRBuilder.h"
34#include "flang/Optimizer/Builder/HLFIRTools.h"
35#include "flang/Optimizer/Builder/Todo.h"
36#include "flang/Optimizer/Dialect/FIRType.h"
37#include "flang/Optimizer/HLFIR/HLFIROps.h"
38#include "flang/Parser/parse-tree.h"
39#include "flang/Semantics/openmp-directive-sets.h"
40#include "flang/Semantics/tools.h"
41#include "mlir/Dialect/OpenACC/OpenACC.h"
42#include "mlir/Dialect/OpenMP/OpenMPDialect.h"
43#include "mlir/Dialect/SCF/IR/SCF.h"
44#include "mlir/IR/Value.h"
45#include "llvm/Frontend/OpenMP/OMPConstants.h"
57 : addr(addr), rawInput(rawInput) {}
59 mlir::Value isPresent)
60 : addr(addr), rawInput(rawInput), isPresent(isPresent) {}
62 mlir::Value isPresent, mlir::Type boxType)
63 : addr(addr), rawInput(rawInput), isPresent(isPresent), boxType(boxType) {
65 mlir::Value addr =
nullptr;
66 mlir::Value rawInput =
nullptr;
67 mlir::Value isPresent =
nullptr;
68 mlir::Type boxType =
nullptr;
69 void dump(llvm::raw_ostream &os) {
70 os <<
"AddrAndBoundsInfo addr: " << addr <<
"\n";
71 os <<
"AddrAndBoundsInfo rawInput: " << rawInput <<
"\n";
72 os <<
"AddrAndBoundsInfo isPresent: " << isPresent <<
"\n";
73 os <<
"AddrAndBoundsInfo boxType: " << boxType <<
"\n";
79static inline void genOmpAtomicHintAndMemoryOrderClauses(
82 mlir::IntegerAttr &hint,
83 mlir::omp::ClauseMemoryOrderKindAttr &memoryOrder) {
86 if (
const auto *ompClause =
87 std::get_if<Fortran::parser::OmpClause>(&clause.u)) {
88 if (
const auto *hintClause =
89 std::get_if<Fortran::parser::OmpClause::Hint>(&ompClause->u)) {
90 const auto *expr = Fortran::semantics::GetExpr(hintClause->v);
91 uint64_t hintExprValue = *Fortran::evaluate::ToInt64(*expr);
92 hint = firOpBuilder.getI64IntegerAttr(hintExprValue);
94 }
else if (
const auto *ompMemoryOrderClause =
95 std::get_if<Fortran::parser::OmpMemoryOrderClause>(
97 if (std::get_if<Fortran::parser::OmpClause::Acquire>(
98 &ompMemoryOrderClause->v.u)) {
99 memoryOrder = mlir::omp::ClauseMemoryOrderKindAttr::get(
100 firOpBuilder.getContext(),
101 mlir::omp::ClauseMemoryOrderKind::Acquire);
102 }
else if (std::get_if<Fortran::parser::OmpClause::Relaxed>(
103 &ompMemoryOrderClause->v.u)) {
104 memoryOrder = mlir::omp::ClauseMemoryOrderKindAttr::get(
105 firOpBuilder.getContext(),
106 mlir::omp::ClauseMemoryOrderKind::Relaxed);
107 }
else if (std::get_if<Fortran::parser::OmpClause::SeqCst>(
108 &ompMemoryOrderClause->v.u)) {
109 memoryOrder = mlir::omp::ClauseMemoryOrderKindAttr::get(
110 firOpBuilder.getContext(),
111 mlir::omp::ClauseMemoryOrderKind::Seq_cst);
112 }
else if (std::get_if<Fortran::parser::OmpClause::Release>(
113 &ompMemoryOrderClause->v.u)) {
114 memoryOrder = mlir::omp::ClauseMemoryOrderKindAttr::get(
115 firOpBuilder.getContext(),
116 mlir::omp::ClauseMemoryOrderKind::Release);
122template <
typename AtomicListT>
123static void processOmpAtomicTODO(mlir::Type elementType,
124 [[maybe_unused]] mlir::Location loc) {
127 if constexpr (std::is_same<AtomicListT,
130 "is supported type for omp atomic");
136template <
typename AtomicListT>
137static inline void genOmpAccAtomicCaptureStatement(
139 mlir::Value toAddress,
140 [[maybe_unused]]
const AtomicListT *leftHandClauseList,
141 [[maybe_unused]]
const AtomicListT *rightHandClauseList,
142 mlir::Type elementType, mlir::Location loc) {
146 processOmpAtomicTODO<AtomicListT>(elementType, loc);
148 if constexpr (std::is_same<AtomicListT,
152 mlir::IntegerAttr hint =
nullptr;
154 mlir::omp::ClauseMemoryOrderKindAttr memoryOrder =
nullptr;
155 if (leftHandClauseList)
156 genOmpAtomicHintAndMemoryOrderClauses(converter, *leftHandClauseList,
158 if (rightHandClauseList)
159 genOmpAtomicHintAndMemoryOrderClauses(converter, *rightHandClauseList,
161 firOpBuilder.create<mlir::omp::AtomicReadOp>(
162 loc, fromAddress, toAddress, mlir::TypeAttr::get(elementType), hint,
165 firOpBuilder.create<mlir::acc::AtomicReadOp>(
166 loc, fromAddress, toAddress, mlir::TypeAttr::get(elementType));
172template <
typename AtomicListT>
173static inline void genOmpAccAtomicWriteStatement(
175 mlir::Value rhsExpr, [[maybe_unused]]
const AtomicListT *leftHandClauseList,
176 [[maybe_unused]]
const AtomicListT *rightHandClauseList, mlir::Location loc,
177 mlir::Value *evaluatedExprValue =
nullptr) {
181 mlir::Type varType = fir::unwrapRefType(lhsAddr.getType());
183 auto insertionPoint = firOpBuilder.saveInsertionPoint();
184 firOpBuilder.setInsertionPointAfter(rhsExpr.getDefiningOp());
186 firOpBuilder.restoreInsertionPoint(insertionPoint);
188 processOmpAtomicTODO<AtomicListT>(varType, loc);
190 if constexpr (std::is_same<AtomicListT,
194 mlir::IntegerAttr hint =
nullptr;
195 mlir::omp::ClauseMemoryOrderKindAttr memoryOrder =
nullptr;
196 if (leftHandClauseList)
197 genOmpAtomicHintAndMemoryOrderClauses(converter, *leftHandClauseList,
199 if (rightHandClauseList)
200 genOmpAtomicHintAndMemoryOrderClauses(converter, *rightHandClauseList,
202 firOpBuilder.create<mlir::omp::AtomicWriteOp>(loc, lhsAddr, rhsExpr, hint,
205 firOpBuilder.create<mlir::acc::AtomicWriteOp>(loc, lhsAddr, rhsExpr);
211template <
typename AtomicListT>
212static inline void genOmpAccAtomicUpdateStatement(
216 [[maybe_unused]]
const AtomicListT *leftHandClauseList,
217 [[maybe_unused]]
const AtomicListT *rightHandClauseList, mlir::Location loc,
218 mlir::Operation *atomicCaptureOp =
nullptr) {
237 auto getArgExpression =
238 [](std::list<parser::ActualArgSpec>::const_iterator it) {
239 const auto &arg{std::get<parser::ActualArg>((*it).t)};
240 const auto *parserExpr{
241 std::get_if<common::Indirection<parser::Expr>>(&arg.u)};
247 Fortran::lower::ExprToValueMap exprValueOverrides;
251 Fortran::common::visit(
253 [&](
const common::Indirection<parser::FunctionReference> &funcRef)
255 const auto &args{std::get<std::list<parser::ActualArgSpec>>(
256 funcRef.value().v.t)};
257 std::list<parser::ActualArgSpec>::const_iterator beginIt =
259 std::list<parser::ActualArgSpec>::const_iterator endIt = args.end();
260 const auto *exprFirst{getArgExpression(beginIt)};
261 if (exprFirst && exprFirst->value().source ==
262 assignmentStmtVariable.GetSource()) {
269 std::list<parser::ActualArgSpec>::const_iterator it;
270 for (it = beginIt; it != endIt; it++) {
271 const common::Indirection<parser::Expr> *expr =
272 getArgExpression(it);
274 nonAtomicSubExprs.push_back(Fortran::semantics::GetExpr(*expr));
277 [&](
const auto &op) ->
void {
278 using T = std::decay_t<
decltype(op)>;
279 if constexpr (std::is_base_of<
282 const auto &exprLeft{std::get<0>(op.t)};
283 const auto &exprRight{std::get<1>(op.t)};
284 if (exprLeft.value().source == assignmentStmtVariable.GetSource())
285 nonAtomicSubExprs.push_back(
286 Fortran::semantics::GetExpr(exprRight));
288 nonAtomicSubExprs.push_back(
289 Fortran::semantics::GetExpr(exprLeft));
293 assignmentStmtExpr.u);
294 StatementContext nonAtomicStmtCtx;
295 if (!nonAtomicSubExprs.empty()) {
297 auto insertionPoint = firOpBuilder.saveInsertionPoint();
299 firOpBuilder.setInsertionPoint(atomicCaptureOp);
300 mlir::Value nonAtomicVal;
301 for (
auto *nonAtomicSubExpr : nonAtomicSubExprs) {
303 currentLocation, *nonAtomicSubExpr, nonAtomicStmtCtx));
304 exprValueOverrides.try_emplace(nonAtomicSubExpr, nonAtomicVal);
307 firOpBuilder.restoreInsertionPoint(insertionPoint);
310 mlir::Operation *atomicUpdateOp =
nullptr;
311 if constexpr (std::is_same<AtomicListT,
315 mlir::IntegerAttr hint =
nullptr;
316 mlir::omp::ClauseMemoryOrderKindAttr memoryOrder =
nullptr;
317 if (leftHandClauseList)
318 genOmpAtomicHintAndMemoryOrderClauses(converter, *leftHandClauseList,
320 if (rightHandClauseList)
321 genOmpAtomicHintAndMemoryOrderClauses(converter, *rightHandClauseList,
323 atomicUpdateOp = firOpBuilder.create<mlir::omp::AtomicUpdateOp>(
324 currentLocation, lhsAddr, hint, memoryOrder);
326 atomicUpdateOp = firOpBuilder.create<mlir::acc::AtomicUpdateOp>(
327 currentLocation, lhsAddr);
330 processOmpAtomicTODO<AtomicListT>(varType, loc);
334 firOpBuilder.createBlock(&atomicUpdateOp->getRegion(0), {}, varTys, locs);
336 fir::getBase(atomicUpdateOp->getRegion(0).front().getArgument(0));
338 exprValueOverrides.try_emplace(
339 Fortran::semantics::GetExpr(assignmentStmtVariable), val);
345 *Fortran::semantics::GetExpr(assignmentStmtExpr), atomicStmtCtx));
346 mlir::Value convertResult =
347 firOpBuilder.
createConvert(currentLocation, varType, rhsExpr);
348 if constexpr (std::is_same<AtomicListT,
350 firOpBuilder.create<mlir::omp::YieldOp>(currentLocation, convertResult);
352 firOpBuilder.create<mlir::acc::YieldOp>(currentLocation, convertResult);
354 converter.resetExprOverrides();
356 firOpBuilder.setInsertionPointAfter(atomicUpdateOp);
360template <
typename AtomicT,
typename AtomicListT>
362 const AtomicT &atomicWrite, 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>(atomicWrite.t);
369 leftHandClauseList = &std::get<0>(atomicWrite.t);
373 std::get<Fortran::parser::Statement<Fortran::parser::AssignmentStmt>>(
379 mlir::Value rhsExpr =
381 mlir::Value lhsAddr =
383 genOmpAccAtomicWriteStatement(converter, lhsAddr, rhsExpr, leftHandClauseList,
384 rightHandClauseList, loc);
388template <
typename AtomicT,
typename AtomicListT>
390 const AtomicT &atomicRead, mlir::Location loc) {
391 const AtomicListT *rightHandClauseList =
nullptr;
392 const AtomicListT *leftHandClauseList =
nullptr;
393 if constexpr (std::is_same<AtomicListT,
396 rightHandClauseList = &std::get<2>(atomicRead.t);
397 leftHandClauseList = &std::get<0>(atomicRead.t);
400 const auto &assignmentStmtExpr = std::get<Fortran::parser::Expr>(
404 const auto &assignmentStmtVariable = std::get<Fortran::parser::Variable>(
411 *Fortran::semantics::GetExpr(assignmentStmtExpr);
412 mlir::Type elementType = converter.
genType(fromExpr);
413 mlir::Value fromAddress =
416 *Fortran::semantics::GetExpr(assignmentStmtVariable), stmtCtx));
417 genOmpAccAtomicCaptureStatement(converter, fromAddress, toAddress,
418 leftHandClauseList, rightHandClauseList,
423template <
typename AtomicT,
typename AtomicListT>
425 const AtomicT &atomicUpdate, mlir::Location loc) {
426 const AtomicListT *rightHandClauseList =
nullptr;
427 const AtomicListT *leftHandClauseList =
nullptr;
428 if constexpr (std::is_same<AtomicListT,
431 rightHandClauseList = &std::get<2>(atomicUpdate.t);
432 leftHandClauseList = &std::get<0>(atomicUpdate.t);
435 const auto &assignmentStmtExpr = std::get<Fortran::parser::Expr>(
439 const auto &assignmentStmtVariable = std::get<Fortran::parser::Variable>(
446 *Fortran::semantics::GetExpr(assignmentStmtVariable), stmtCtx));
447 mlir::Type varType = fir::unwrapRefType(lhsAddr.getType());
448 genOmpAccAtomicUpdateStatement<AtomicListT>(
449 converter, lhsAddr, varType, assignmentStmtVariable, assignmentStmtExpr,
450 leftHandClauseList, rightHandClauseList, loc);
454template <
typename AtomicT,
typename AtomicListT>
456 const AtomicT &atomicConstruct, mlir::Location loc) {
457 const AtomicListT &atomicClauseList =
458 std::get<AtomicListT>(atomicConstruct.t);
459 const auto &assignmentStmtExpr = std::get<Fortran::parser::Expr>(
463 const auto &assignmentStmtVariable = std::get<Fortran::parser::Variable>(
469 *Fortran::semantics::GetExpr(assignmentStmtVariable), stmtCtx));
470 mlir::Type varType = fir::unwrapRefType(lhsAddr.getType());
473 genOmpAccAtomicUpdateStatement<AtomicListT>(
474 converter, lhsAddr, varType, assignmentStmtVariable, assignmentStmtExpr,
475 &atomicClauseList,
nullptr, loc);
479template <
typename AtomicT,
typename AtomicListT>
481 const AtomicT &atomicCapture, mlir::Location loc) {
485 std::get<typename AtomicT::Stmt1>(atomicCapture.t).v.statement;
487 const auto &stmt1Var{std::get<Fortran::parser::Variable>(stmt1.t)};
488 const auto &stmt1Expr{std::get<Fortran::parser::Expr>(stmt1.t)};
490 std::get<typename AtomicT::Stmt2>(atomicCapture.t).v.statement;
492 const auto &stmt2Var{std::get<Fortran::parser::Variable>(stmt2.t)};
493 const auto &stmt2Expr{std::get<Fortran::parser::Expr>(stmt2.t)};
501 mlir::Value stmt1LHSArg =
503 mlir::Value stmt2LHSArg =
507 mlir::Type stmt1VarType =
509 mlir::Type stmt2VarType =
512 mlir::Operation *atomicCaptureOp =
nullptr;
513 if constexpr (std::is_same<AtomicListT,
515 mlir::IntegerAttr hint =
nullptr;
516 mlir::omp::ClauseMemoryOrderKindAttr memoryOrder =
nullptr;
517 const AtomicListT &rightHandClauseList = std::get<2>(atomicCapture.t);
518 const AtomicListT &leftHandClauseList = std::get<0>(atomicCapture.t);
519 genOmpAtomicHintAndMemoryOrderClauses(converter, leftHandClauseList, hint,
521 genOmpAtomicHintAndMemoryOrderClauses(converter, rightHandClauseList, hint,
524 firOpBuilder.create<mlir::omp::AtomicCaptureOp>(loc, hint, memoryOrder);
526 atomicCaptureOp = firOpBuilder.create<mlir::acc::AtomicCaptureOp>(loc);
529 firOpBuilder.createBlock(&(atomicCaptureOp->getRegion(0)));
530 mlir::Block &block = atomicCaptureOp->getRegion(0).back();
531 firOpBuilder.setInsertionPointToStart(&block);
532 if (Fortran::semantics::checkForSingleVariableOnRHS(stmt1)) {
533 if (Fortran::semantics::checkForSymbolMatch(stmt2)) {
536 *Fortran::semantics::GetExpr(stmt1Expr);
537 mlir::Type elementType = converter.
genType(fromExpr);
538 genOmpAccAtomicCaptureStatement<AtomicListT>(
539 converter, stmt2LHSArg, stmt1LHSArg,
541 nullptr, elementType, loc);
542 genOmpAccAtomicUpdateStatement<AtomicListT>(
543 converter, stmt2LHSArg, stmt2VarType, stmt2Var, stmt2Expr,
545 nullptr, loc, atomicCaptureOp);
548 firOpBuilder.setInsertionPoint(atomicCaptureOp);
549 mlir::Value stmt2RHSArg =
551 firOpBuilder.setInsertionPointToStart(&block);
553 *Fortran::semantics::GetExpr(stmt1Expr);
554 mlir::Type elementType = converter.
genType(fromExpr);
555 genOmpAccAtomicCaptureStatement<AtomicListT>(
556 converter, stmt2LHSArg, stmt1LHSArg,
558 nullptr, elementType, loc);
559 genOmpAccAtomicWriteStatement<AtomicListT>(
560 converter, stmt2LHSArg, stmt2RHSArg,
567 *Fortran::semantics::GetExpr(stmt2Expr);
568 mlir::Type elementType = converter.
genType(fromExpr);
569 genOmpAccAtomicUpdateStatement<AtomicListT>(
570 converter, stmt1LHSArg, stmt1VarType, stmt1Var, stmt1Expr,
572 nullptr, loc, atomicCaptureOp);
573 genOmpAccAtomicCaptureStatement<AtomicListT>(
574 converter, stmt1LHSArg, stmt2LHSArg,
576 nullptr, elementType, loc);
578 firOpBuilder.setInsertionPointToEnd(&block);
579 if constexpr (std::is_same<AtomicListT,
581 firOpBuilder.create<mlir::omp::TerminatorOp>(loc);
583 firOpBuilder.create<mlir::acc::TerminatorOp>(loc);
585 firOpBuilder.setInsertionPointToStart(&block);
590template <
typename... TerminatorOps>
593 std::list<Fortran::lower::pft::Evaluation> &evaluationList) {
594 mlir::Region *region = &builder.
getRegion();
597 if (eval.block->empty()) {
599 eval.block = builder.createBlock(region);
601 [[maybe_unused]] mlir::Operation &terminatorOp = eval.block->back();
602 assert(mlir::isa<TerminatorOps...>(terminatorOp) &&
603 "expected terminator op");
606 if (!eval.isDirective() && eval.hasNestedEvaluations())
608 eval.getNestedEvaluations());
615 mlir::Location loc) {
616 mlir::Value rawInput = symAddr;
618 mlir::dyn_cast_or_null<hlfir::DeclareOp>(symAddr.getDefiningOp())) {
619 symAddr = declareOp.getResults()[0];
620 rawInput = declareOp.getResults()[1];
624 llvm::report_fatal_error(
"could not retrieve symbol address");
626 mlir::Value isPresent;
629 builder.create<fir::IsPresentOp>(loc, builder.getI1Type(), rawInput);
631 if (
auto boxTy = mlir::dyn_cast<fir::BaseBoxType>(
632 fir::unwrapRefType(symAddr.getType()))) {
633 if (mlir::isa<fir::RecordType>(boxTy.getEleTy()))
634 TODO(loc,
"derived type");
641 if (mlir::isa<fir::ReferenceType>(symAddr.getType()) && !isOptional) {
642 mlir::Value addr = builder.create<fir::LoadOp>(loc, symAddr);
643 return AddrAndBoundsInfo(addr, rawInput, isPresent, boxTy);
646 return AddrAndBoundsInfo(symAddr, rawInput, isPresent, boxTy);
648 return AddrAndBoundsInfo(symAddr, rawInput, isPresent);
651inline AddrAndBoundsInfo
656 Fortran::semantics::IsOptional(sym), loc);
659template <
typename BoundsOp,
typename BoundsType>
663 bool collectValuesOnly =
false) {
664 assert(box &&
"box must exist");
666 mlir::Value byteStride;
667 mlir::Type idxTy = builder.getIndexType();
668 mlir::Type boundTy = builder.getType<BoundsType>();
670 for (
unsigned dim = 0; dim < dataExv.rank(); ++dim) {
673 fir::factory::readLowerBound(builder, loc, dataExv, dim, one);
675 builder.create<fir::BoxDimsOp>(loc, idxTy, idxTy, idxTy, box, d);
678 builder.create<mlir::arith::SubIOp>(loc, dimInfo.getExtent(), one);
680 byteStride = dimInfo.getByteStride();
681 if (collectValuesOnly) {
682 values.push_back(lb);
683 values.push_back(ub);
684 values.push_back(dimInfo.getExtent());
685 values.push_back(byteStride);
686 values.push_back(baseLb);
688 mlir::Value bound = builder.create<BoundsOp>(
689 loc, boundTy, lb, ub, dimInfo.getExtent(), byteStride,
true, baseLb);
690 values.push_back(bound);
693 byteStride = builder.create<mlir::arith::MulIOp>(loc, byteStride,
694 dimInfo.getExtent());
700template <
typename BoundsOp,
typename BoundsType>
706 mlir::Type idxTy = builder.getIndexType();
707 mlir::Type boundTy = builder.getType<BoundsType>();
709 assert(mlir::isa<fir::BaseBoxType>(info.boxType) &&
710 "expect fir.box or fir.class");
711 assert(fir::unwrapRefType(info.addr.getType()) == info.boxType &&
712 "expected box type consistency");
714 if (info.isPresent) {
716 constexpr unsigned nbValuesPerBound = 5;
717 for (
unsigned dim = 0; dim < dataExv.rank() * nbValuesPerBound; ++dim)
718 resTypes.push_back(idxTy);
720 mlir::Operation::result_range ifRes =
721 builder.
genIfOp(loc, resTypes, info.isPresent,
true)
726 : builder.create<fir::LoadOp>(loc, info.addr);
728 gatherBoundsOrBoundValues<BoundsOp, BoundsType>(
729 builder, loc, dataExv, box,
731 builder.create<fir::ResultOp>(loc, boundValues);
738 for (
unsigned dim = 0; dim < dataExv.rank(); ++dim) {
739 boundValues.push_back(zero);
740 boundValues.push_back(mOne);
741 boundValues.push_back(zero);
742 boundValues.push_back(zero);
743 boundValues.push_back(zero);
745 builder.create<fir::ResultOp>(loc, boundValues);
750 for (
unsigned i = 0; i < ifRes.size(); i += nbValuesPerBound) {
751 mlir::Value bound = builder.create<BoundsOp>(
752 loc, boundTy, ifRes[i], ifRes[i + 1], ifRes[i + 2], ifRes[i + 3],
754 bounds.push_back(bound);
759 : builder.create<fir::LoadOp>(loc, info.addr);
760 bounds = gatherBoundsOrBoundValues<BoundsOp, BoundsType>(builder, loc,
768template <
typename BoundsOp,
typename BoundsType>
772 mlir::Type idxTy = builder.getIndexType();
773 mlir::Type boundTy = builder.getType<BoundsType>();
776 if (dataExv.rank() == 0)
780 const unsigned rank = dataExv.rank();
781 for (
unsigned dim = 0; dim < rank; ++dim) {
783 fir::factory::readLowerBound(builder, loc, dataExv, dim, one);
786 mlir::Value lb = zero;
787 mlir::Value ext = fir::factory::readExtent(builder, loc, dataExv, dim);
788 if (isAssumedSize && dim + 1 == rank) {
793 ub = builder.create<mlir::arith::SubIOp>(loc, ext, one);
797 builder.create<BoundsOp>(loc, boundTy, lb, ub, ext, one,
false, baseLb);
798 bounds.push_back(bound);
805static T &&AsRvalueRef(T &&t) {
809static T AsRvalueRef(T &t) {
813static T AsRvalueRef(
const T &t) {
824 template <Fortran::common::TypeCategory Category,
int Kind>
825 static Fortran::semantics::MaybeExpr visit_with_category(
828 return Fortran::common::visit(
829 [](
auto &&s) {
return visit_with_category<Category, Kind>(s); },
832 template <Fortran::common::TypeCategory Category,
int Kind>
833 static Fortran::semantics::MaybeExpr visit_with_category(
836 return AsGenericExpr(AsRvalueRef(expr.left()));
838 template <Fortran::common::TypeCategory Category,
int Kind,
typename T>
839 static Fortran::semantics::MaybeExpr visit_with_category(
const T &) {
842 template <Fortran::common::TypeCategory Category,
typename T>
843 static Fortran::semantics::MaybeExpr visit_with_category(
const T &) {
847 template <Fortran::common::TypeCategory Category>
848 static Fortran::semantics::MaybeExpr
851 return Fortran::common::visit(
852 [](
auto &&s) {
return visit_with_category<Category>(s); }, expr.u);
854 static Fortran::semantics::MaybeExpr
856 return Fortran::common::visit([](
auto &&s) {
return visit(s); }, expr.u);
858 template <
typename T>
859 static Fortran::semantics::MaybeExpr visit(
const T &) {
866 if (
auto peeled = PeelConvert::visit(expr))
874template <
typename BoundsOp,
typename BoundsType>
879 const std::vector<Fortran::evaluate::Subscript> &subscripts,
882 bool treatIndexAsSection =
false) {
884 mlir::Type idxTy = builder.getIndexType();
885 mlir::Type boundTy = builder.getType<BoundsType>();
890 const int dataExvRank =
static_cast<int>(dataExv.rank());
891 for (
const auto &subscript : subscripts) {
892 const auto *triplet{std::get_if<Fortran::evaluate::Triplet>(&subscript.u)};
893 if (triplet || treatIndexAsSection) {
896 mlir::Value lbound, ubound, extent;
897 std::optional<std::int64_t> lval, uval;
899 fir::factory::readLowerBound(builder, loc, dataExv, dimension, one);
900 bool defaultLb = baseLb == one;
901 mlir::Value stride = one;
902 bool strideInBytes =
false;
904 if (mlir::isa<fir::BaseBoxType>(
905 fir::unwrapRefType(info.addr.getType()))) {
906 if (info.isPresent) {
909 .
genIfOp(loc, idxTy, info.isPresent,
true)
914 : builder.create<fir::LoadOp>(loc, info.addr);
917 auto dimInfo = builder.create<fir::BoxDimsOp>(
918 loc, idxTy, idxTy, idxTy, box, d);
919 builder.create<fir::ResultOp>(loc, dimInfo.getByteStride());
924 builder.create<fir::ResultOp>(loc, zero);
930 : builder.create<fir::LoadOp>(loc, info.addr);
933 builder.create<fir::BoxDimsOp>(loc, idxTy, idxTy, idxTy, box, d);
934 stride = dimInfo.getByteStride();
936 strideInBytes =
true;
939 Fortran::semantics::MaybeExpr lower;
941 lower = Fortran::evaluate::AsGenericExpr(triplet->lower());
948 std::get<IndirectSubscriptIntegerExpr>(subscript.u).value();
949 lower = Fortran::evaluate::AsGenericExpr(std::move(oneInt));
950 if (lower->Rank() > 0) {
952 loc,
"vector subscript cannot be used for an array section");
957 lval = Fortran::evaluate::ToInt64(*lower);
963 lbound = builder.create<mlir::arith::SubIOp>(loc, lb, baseLb);
970 lbound = builder.create<mlir::arith::SubIOp>(loc, lb, baseLb);
971 asFortran << detail::peelOuterConvert(*lower).AsFortran();
987 Fortran::semantics::MaybeExpr upper =
988 Fortran::evaluate::AsGenericExpr(triplet->upper());
991 uval = Fortran::evaluate::ToInt64(*upper);
997 ubound = builder.create<mlir::arith::SubIOp>(loc, ub, baseLb);
1004 ubound = builder.create<mlir::arith::SubIOp>(loc, ub, baseLb);
1005 asFortran << detail::peelOuterConvert(*upper).AsFortran();
1008 if (lower && upper) {
1009 if (lval && uval && *uval < *lval) {
1010 mlir::emitError(loc,
"zero sized array section");
1014 auto val = Fortran::evaluate::ToInt64(triplet->GetStride());
1015 if (!val || *val != 1) {
1016 mlir::emitError(loc,
"stride cannot be specified on "
1017 "an array section");
1023 if (info.isPresent && mlir::isa<fir::BaseBoxType>(
1024 fir::unwrapRefType(info.addr.getType()))) {
1027 .
genIfOp(loc, idxTy, info.isPresent,
true)
1029 mlir::Value ext = fir::factory::readExtent(
1030 builder, loc, dataExv, dimension);
1031 builder.create<fir::ResultOp>(loc, ext);
1036 builder.create<fir::ResultOp>(loc, zero);
1040 extent = fir::factory::readExtent(builder, loc, dataExv, dimension);
1043 if (dataExvIsAssumedSize && dimension + 1 == dataExvRank) {
1045 if (ubound && lbound) {
1047 builder.create<mlir::arith::SubIOp>(loc, ubound, lbound);
1048 extent = builder.create<mlir::arith::AddIOp>(loc, diff, one);
1056 ubound = builder.create<mlir::arith::SubIOp>(loc, extent, one);
1059 mlir::Value bound = builder.create<BoundsOp>(
1060 loc, boundTy, lbound, ubound, extent, stride, strideInBytes, baseLb);
1061 bounds.push_back(bound);
1069template <
typename Ref,
typename Expr>
1070std::optional<Ref> getRef(Expr &&expr) {
1071 if constexpr (std::is_same_v<llvm::remove_cvref_t<Expr>,
1073 if (
auto *ref = std::get_if<Ref>(&expr.u))
1075 return std::nullopt;
1077 auto maybeRef = Fortran::evaluate::ExtractDataRef(expr);
1078 if (!maybeRef || !std::holds_alternative<Ref>(maybeRef->u))
1079 return std::nullopt;
1080 return std::get<Ref>(maybeRef->u);
1085template <
typename BoundsOp,
typename BoundsType>
1086AddrAndBoundsInfo gatherDataOperandAddrAndBounds(
1088 semantics::SemanticsContext &semaCtx,
1091 const Fortran::semantics::MaybeExpr &maybeDesignator,
1092 mlir::Location operandLocation, std::stringstream &asFortran,
1096 AddrAndBoundsInfo info;
1098 if (!maybeDesignator) {
1099 info = getDataOperandBaseAddr(converter, builder, symbol, operandLocation);
1100 asFortran << symbol->name().ToString();
1106 if ((designator.Rank() > 0 || treatIndexAsSection) &&
1107 IsArrayElement(designator)) {
1108 auto arrayRef = detail::getRef<evaluate::ArrayRef>(designator);
1110 assert(arrayRef &&
"Expecting ArrayRef");
1113 bool dataExvIsAssumedSize =
false;
1115 auto toMaybeExpr = [&](
auto &&base) {
1116 using BaseType = llvm::remove_cvref_t<
decltype(base)>;
1119 if constexpr (std::is_same_v<evaluate::NamedEntity, BaseType>) {
1120 if (
auto *ref = base.UnwrapSymbolRef())
1122 if (
auto *ref = base.UnwrapComponent())
1124 llvm_unreachable(
"Unexpected NamedEntity");
1126 static_assert(std::is_same_v<semantics::SymbolRef, BaseType>);
1131 auto arrayBase = toMaybeExpr(arrayRef->base());
1134 if (detail::getRef<evaluate::Component>(*arrayBase)) {
1135 dataExv = converter.
genExprAddr(operandLocation, *arrayBase, stmtCtx);
1137 info.rawInput = info.addr;
1138 asFortran << arrayBase->AsFortran();
1141 dataExvIsAssumedSize =
1142 Fortran::semantics::IsAssumedSizeArray(sym.GetUltimate());
1143 info = getDataOperandBaseAddr(converter, builder, sym, operandLocation);
1144 dataExv = converter.getSymbolExtendedValue(sym);
1145 asFortran << sym.name().ToString();
1148 if (!arrayRef->subscript().empty()) {
1150 bounds = genBoundsOps<BoundsOp, BoundsType>(
1151 builder, operandLocation, converter, stmtCtx, arrayRef->subscript(),
1152 asFortran, dataExv, dataExvIsAssumedSize, info, treatIndexAsSection);
1155 }
else if (
auto compRef = detail::getRef<evaluate::Component>(designator)) {
1157 converter.
genExprAddr(operandLocation, designator, stmtCtx);
1159 info.rawInput = info.addr;
1160 if (mlir::isa<fir::SequenceType>(fir::unwrapRefType(info.addr.getType())))
1161 bounds = genBaseBoundsOps<BoundsOp, BoundsType>(builder, operandLocation,
1164 asFortran << designator.AsFortran();
1166 if (semantics::IsOptional(compRef->GetLastSymbol())) {
1167 info.isPresent = builder.create<fir::IsPresentOp>(
1168 operandLocation, builder.getI1Type(), info.rawInput);
1172 mlir::dyn_cast_or_null<fir::LoadOp>(info.addr.getDefiningOp())) {
1175 info.boxType = info.addr.getType();
1176 info.addr = builder.create<fir::BoxAddrOp>(operandLocation, info.addr);
1178 info.rawInput = info.addr;
1185 if (
auto boxAddrOp =
1186 mlir::dyn_cast_or_null<fir::BoxAddrOp>(info.addr.getDefiningOp())) {
1187 info.addr = boxAddrOp.getVal();
1188 info.boxType = info.addr.getType();
1189 info.rawInput = info.addr;
1190 bounds = genBoundsOpsFromBox<BoundsOp, BoundsType>(
1191 builder, operandLocation, compExv, info);
1194 if (detail::getRef<evaluate::ArrayRef>(designator)) {
1196 converter.
genExprAddr(operandLocation, designator, stmtCtx);
1198 info.rawInput = info.addr;
1199 asFortran << designator.AsFortran();
1200 }
else if (
auto symRef = detail::getRef<semantics::SymbolRef>(designator)) {
1204 getDataOperandBaseAddr(converter, builder, *symRef, operandLocation);
1205 if (mlir::isa<fir::BaseBoxType>(
1206 fir::unwrapRefType(info.addr.getType()))) {
1207 info.boxType = fir::unwrapRefType(info.addr.getType());
1208 bounds = genBoundsOpsFromBox<BoundsOp, BoundsType>(
1209 builder, operandLocation, dataExv, info);
1211 bool dataExvIsAssumedSize =
1212 Fortran::semantics::IsAssumedSizeArray(symRef->get().GetUltimate());
1213 if (mlir::isa<fir::SequenceType>(fir::unwrapRefType(info.addr.getType())))
1214 bounds = genBaseBoundsOps<BoundsOp, BoundsType>(
1215 builder, operandLocation, dataExv, dataExvIsAssumedSize);
1216 asFortran << symRef->get().name().ToString();
1218 llvm::report_fatal_error(
"Unsupported type of OpenACC operand");
1225template <
typename BoundsOp,
typename BoundsType>
1229 mlir::Location loc) {
1232 mlir::Value baseOp = info.rawInput;
1233 if (mlir::isa<fir::BaseBoxType>(fir::unwrapRefType(baseOp.getType())))
1234 bounds = lower::genBoundsOpsFromBox<BoundsOp, BoundsType>(builder, loc,
1236 if (mlir::isa<fir::SequenceType>(fir::unwrapRefType(baseOp.getType()))) {
1237 bounds = lower::genBaseBoundsOps<BoundsOp, BoundsType>(
1238 builder, loc, dataExv, dataExvIsAssumedSize);
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::Value createMinusOneInteger(mlir::Location loc, mlir::Type integerType)
Definition: FIRBuilder.h:187
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 > genBoundsOpsFromBox(fir::FirOpBuilder &builder, mlir::Location loc, fir::ExtendedValue dataExv, Fortran::lower::AddrAndBoundsInfo &info)
Generate the bounds operation from the descriptor information.
Definition: DirectivesCommon.h:702
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, AddrAndBoundsInfo &info, bool treatIndexAsSection=false)
Definition: DirectivesCommon.h:876
void genOmpAccAtomicRead(Fortran::lower::AbstractConverter &converter, const AtomicT &atomicRead, mlir::Location loc)
Processes an atomic construct with read clause.
Definition: DirectivesCommon.h:389
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:455
llvm::SmallVector< mlir::Value > genBaseBoundsOps(fir::FirOpBuilder &builder, mlir::Location loc, fir::ExtendedValue dataExv, bool isAssumedSize)
Definition: DirectivesCommon.h:770
void genOmpAccAtomicUpdate(Fortran::lower::AbstractConverter &converter, const AtomicT &atomicUpdate, mlir::Location loc)
Processes an atomic construct with update clause.
Definition: DirectivesCommon.h:424
void createEmptyRegionBlocks(fir::FirOpBuilder &builder, std::list< Fortran::lower::pft::Evaluation > &evaluationList)
Definition: DirectivesCommon.h:591
void genOmpAccAtomicWrite(Fortran::lower::AbstractConverter &converter, const AtomicT &atomicWrite, mlir::Location loc)
Processes an atomic construct with write clause.
Definition: DirectivesCommon.h:361
void genOmpAccAtomicCapture(Fortran::lower::AbstractConverter &converter, const AtomicT &atomicCapture, mlir::Location loc)
Processes an atomic construct with capture clause.
Definition: DirectivesCommon.h:480
Definition: bit-population-count.h:20
bool isBoxAddress(mlir::Type t)
Is t an address to fir.box or class type?
Definition: FIRType.h:468
mlir::Value getBase(const ExtendedValue &exv)
Definition: BoxValue.cpp:21
bool isPointerType(mlir::Type ty)
Definition: FIRType.cpp:272
bool isAllocatableType(mlir::Type ty)
Return true iff ty is the type of an ALLOCATABLE entity or value.
Definition: FIRType.cpp:280
bool isa_trivial(mlir::Type t)
Definition: FIRType.h:195
Definition: expression.h:211
Definition: variable.h:300
Definition: DirectivesCommon.h:54
Definition: DirectivesCommon.h:823
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