1ae6e499dSEric Schweitz //===-- OpenMP.cpp -- Open MP directive lowering --------------------------===//
2ae6e499dSEric Schweitz //
3ae6e499dSEric Schweitz // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4ae6e499dSEric Schweitz // See https://llvm.org/LICENSE.txt for license information.
5ae6e499dSEric Schweitz // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6ae6e499dSEric Schweitz //
7ae6e499dSEric Schweitz //===----------------------------------------------------------------------===//
83d0b7602SSourabh Singh Tomar //
93d0b7602SSourabh Singh Tomar // Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/
103d0b7602SSourabh Singh Tomar //
113d0b7602SSourabh Singh Tomar //===----------------------------------------------------------------------===//
12ae6e499dSEric Schweitz 
13ae6e499dSEric Schweitz #include "flang/Lower/OpenMP.h"
141d328446SSourabh Singh Tomar #include "flang/Common/idioms.h"
15c3477c51SEric Schweitz #include "flang/Lower/Bridge.h"
16dc4bf2c3SMats Petersson #include "flang/Lower/ConvertExpr.h"
17ae6e499dSEric Schweitz #include "flang/Lower/PFTBuilder.h"
18d0b70a07SValentin Clement #include "flang/Lower/StatementContext.h"
198a0d0a3aSValentin Clement #include "flang/Optimizer/Builder/BoxValue.h"
208a0d0a3aSValentin Clement #include "flang/Optimizer/Builder/FIRBuilder.h"
215b66cc10SValentin Clement #include "flang/Optimizer/Builder/Todo.h"
22ae6e499dSEric Schweitz #include "flang/Parser/parse-tree.h"
2334b08487SSourabh Singh Tomar #include "flang/Semantics/tools.h"
243d0b7602SSourabh Singh Tomar #include "mlir/Dialect/OpenMP/OpenMPDialect.h"
2517d9bdf4SArnamoy Bhattacharyya #include "mlir/Dialect/SCF/IR/SCF.h"
263d0b7602SSourabh Singh Tomar #include "llvm/Frontend/OpenMP/OMPConstants.h"
27ae6e499dSEric Schweitz 
28092601d4SAndrzej Warzynski using namespace mlir;
29092601d4SAndrzej Warzynski 
getCollapseValue(const Fortran::parser::OmpClauseList & clauseList)303b390a16SMats Petersson int64_t Fortran::lower::getCollapseValue(
313b390a16SMats Petersson     const Fortran::parser::OmpClauseList &clauseList) {
323b390a16SMats Petersson   for (const auto &clause : clauseList.v) {
333b390a16SMats Petersson     if (const auto &collapseClause =
343b390a16SMats Petersson             std::get_if<Fortran::parser::OmpClause::Collapse>(&clause.u)) {
353b390a16SMats Petersson       const auto *expr = Fortran::semantics::GetExpr(collapseClause->v);
363b390a16SMats Petersson       return Fortran::evaluate::ToInt64(*expr).value();
373b390a16SMats Petersson     }
383b390a16SMats Petersson   }
393b390a16SMats Petersson   return 1;
403b390a16SMats Petersson }
413b390a16SMats Petersson 
421d328446SSourabh Singh Tomar static const Fortran::parser::Name *
getDesignatorNameIfDataRef(const Fortran::parser::Designator & designator)431d328446SSourabh Singh Tomar getDesignatorNameIfDataRef(const Fortran::parser::Designator &designator) {
441d328446SSourabh Singh Tomar   const auto *dataRef = std::get_if<Fortran::parser::DataRef>(&designator.u);
451d328446SSourabh Singh Tomar   return dataRef ? std::get_if<Fortran::parser::Name>(&dataRef->u) : nullptr;
461d328446SSourabh Singh Tomar }
471d328446SSourabh Singh Tomar 
48bc99d565SPeixinQiao static Fortran::semantics::Symbol *
getOmpObjectSymbol(const Fortran::parser::OmpObject & ompObject)49bc99d565SPeixinQiao getOmpObjectSymbol(const Fortran::parser::OmpObject &ompObject) {
5007e16a2aSKiran Chandramohan   Fortran::semantics::Symbol *sym = nullptr;
51bc99d565SPeixinQiao   std::visit(Fortran::common::visitors{
521d328446SSourabh Singh Tomar                  [&](const Fortran::parser::Designator &designator) {
5307e16a2aSKiran Chandramohan                    if (const Fortran::parser::Name *name =
5407e16a2aSKiran Chandramohan                            getDesignatorNameIfDataRef(designator)) {
5507e16a2aSKiran Chandramohan                      sym = name->symbol;
5607e16a2aSKiran Chandramohan                    }
5707e16a2aSKiran Chandramohan                  },
5807e16a2aSKiran Chandramohan                  [&](const Fortran::parser::Name &name) { sym = name.symbol; }},
5907e16a2aSKiran Chandramohan              ompObject.u);
60bc99d565SPeixinQiao   return sym;
61bc99d565SPeixinQiao }
6207e16a2aSKiran Chandramohan 
63bc99d565SPeixinQiao template <typename T>
createPrivateVarSyms(Fortran::lower::AbstractConverter & converter,const T * clause,Block * lastPrivBlock=nullptr)64bc99d565SPeixinQiao static void createPrivateVarSyms(Fortran::lower::AbstractConverter &converter,
6517d9bdf4SArnamoy Bhattacharyya                                  const T *clause,
6617d9bdf4SArnamoy Bhattacharyya                                  Block *lastPrivBlock = nullptr) {
67bc99d565SPeixinQiao   const Fortran::parser::OmpObjectList &ompObjectList = clause->v;
68bc99d565SPeixinQiao   for (const Fortran::parser::OmpObject &ompObject : ompObjectList.v) {
69bc99d565SPeixinQiao     Fortran::semantics::Symbol *sym = getOmpObjectSymbol(ompObject);
7007e16a2aSKiran Chandramohan     // Privatization for symbols which are pre-determined (like loop index
71c030f467SKiran Chandramohan     // variables) happen separately, for everything else privatize here.
72c030f467SKiran Chandramohan     if (sym->test(Fortran::semantics::Symbol::Flag::OmpPreDetermined))
73c030f467SKiran Chandramohan       continue;
7407e16a2aSKiran Chandramohan     bool success = converter.createHostAssociateVarClone(*sym);
7507e16a2aSKiran Chandramohan     (void)success;
7607e16a2aSKiran Chandramohan     assert(success && "Privatization failed due to existing binding");
7727afb362SPeixin-Qiao     if constexpr (std::is_same_v<T, Fortran::parser::OmpClause::Firstprivate>) {
7827afb362SPeixin-Qiao       converter.copyHostAssociateVar(*sym);
7917d9bdf4SArnamoy Bhattacharyya     } else if constexpr (std::is_same_v<
8017d9bdf4SArnamoy Bhattacharyya                              T, Fortran::parser::OmpClause::Lastprivate>) {
8117d9bdf4SArnamoy Bhattacharyya       converter.copyHostAssociateVar(*sym, lastPrivBlock);
8207e16a2aSKiran Chandramohan     }
8307e16a2aSKiran Chandramohan   }
8407e16a2aSKiran Chandramohan }
8507e16a2aSKiran Chandramohan 
8617d9bdf4SArnamoy Bhattacharyya template <typename Op>
privatizeVars(Op & op,Fortran::lower::AbstractConverter & converter,const Fortran::parser::OmpClauseList & opClauseList)8717d9bdf4SArnamoy Bhattacharyya static bool privatizeVars(Op &op, Fortran::lower::AbstractConverter &converter,
88*f2b7f18eSShraiysh Vaishay                           const Fortran::parser::OmpClauseList &opClauseList) {
8907e16a2aSKiran Chandramohan   fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();
9007e16a2aSKiran Chandramohan   auto insPt = firOpBuilder.saveInsertionPoint();
9107e16a2aSKiran Chandramohan   firOpBuilder.setInsertionPointToStart(firOpBuilder.getAllocaBlock());
92c858f4dbSShraiysh Vaishay   bool hasFirstPrivateOp = false;
9317d9bdf4SArnamoy Bhattacharyya   bool hasLastPrivateOp = false;
9417d9bdf4SArnamoy Bhattacharyya   // We need just one ICmpOp for multiple LastPrivate clauses.
9517d9bdf4SArnamoy Bhattacharyya   mlir::arith::CmpIOp cmpOp;
96*f2b7f18eSShraiysh Vaishay 
9707e16a2aSKiran Chandramohan   for (const Fortran::parser::OmpClause &clause : opClauseList.v) {
9807e16a2aSKiran Chandramohan     if (const auto &privateClause =
9907e16a2aSKiran Chandramohan             std::get_if<Fortran::parser::OmpClause::Private>(&clause.u)) {
100*f2b7f18eSShraiysh Vaishay       createPrivateVarSyms(converter, privateClause);
10107e16a2aSKiran Chandramohan     } else if (const auto &firstPrivateClause =
10207e16a2aSKiran Chandramohan                    std::get_if<Fortran::parser::OmpClause::Firstprivate>(
10307e16a2aSKiran Chandramohan                        &clause.u)) {
104*f2b7f18eSShraiysh Vaishay       createPrivateVarSyms(converter, firstPrivateClause);
105c858f4dbSShraiysh Vaishay       hasFirstPrivateOp = true;
10617d9bdf4SArnamoy Bhattacharyya     } else if (const auto &lastPrivateClause =
10717d9bdf4SArnamoy Bhattacharyya                    std::get_if<Fortran::parser::OmpClause::Lastprivate>(
10817d9bdf4SArnamoy Bhattacharyya                        &clause.u)) {
10917d9bdf4SArnamoy Bhattacharyya       // TODO: Add lastprivate support for sections construct, simd construct
11017d9bdf4SArnamoy Bhattacharyya       if (std::is_same_v<Op, omp::WsLoopOp>) {
11117d9bdf4SArnamoy Bhattacharyya         omp::WsLoopOp *wsLoopOp = dyn_cast<omp::WsLoopOp>(&op);
11217d9bdf4SArnamoy Bhattacharyya         fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();
11317d9bdf4SArnamoy Bhattacharyya         auto insPt = firOpBuilder.saveInsertionPoint();
11417d9bdf4SArnamoy Bhattacharyya 
11517d9bdf4SArnamoy Bhattacharyya         // Our goal here is to introduce the following control flow
11617d9bdf4SArnamoy Bhattacharyya         // just before exiting the worksharing loop.
11717d9bdf4SArnamoy Bhattacharyya         // Say our wsloop is as follows:
11817d9bdf4SArnamoy Bhattacharyya         //
11917d9bdf4SArnamoy Bhattacharyya         // omp.wsloop {
12017d9bdf4SArnamoy Bhattacharyya         //    ...
12117d9bdf4SArnamoy Bhattacharyya         //    store
12217d9bdf4SArnamoy Bhattacharyya         //    omp.yield
12317d9bdf4SArnamoy Bhattacharyya         // }
12417d9bdf4SArnamoy Bhattacharyya         //
12517d9bdf4SArnamoy Bhattacharyya         // We want to convert it to the following:
12617d9bdf4SArnamoy Bhattacharyya         //
12717d9bdf4SArnamoy Bhattacharyya         // omp.wsloop {
12817d9bdf4SArnamoy Bhattacharyya         //    ...
12917d9bdf4SArnamoy Bhattacharyya         //    store
13017d9bdf4SArnamoy Bhattacharyya         //    %cmp = llvm.icmp "eq" %iv %ub
13117d9bdf4SArnamoy Bhattacharyya         //    scf.if %cmp {
13217d9bdf4SArnamoy Bhattacharyya         //      ^%lpv_update_blk:
13317d9bdf4SArnamoy Bhattacharyya         //    }
13417d9bdf4SArnamoy Bhattacharyya         //    omp.yield
13517d9bdf4SArnamoy Bhattacharyya         // }
13617d9bdf4SArnamoy Bhattacharyya 
13717d9bdf4SArnamoy Bhattacharyya         Operation *lastOper = wsLoopOp->region().back().getTerminator();
13817d9bdf4SArnamoy Bhattacharyya 
13917d9bdf4SArnamoy Bhattacharyya         firOpBuilder.setInsertionPoint(lastOper);
14017d9bdf4SArnamoy Bhattacharyya 
14117d9bdf4SArnamoy Bhattacharyya         // TODO: The following will not work when there is collapse present.
14217d9bdf4SArnamoy Bhattacharyya         // Have to modify this in future.
14317d9bdf4SArnamoy Bhattacharyya         for (const Fortran::parser::OmpClause &clause : opClauseList.v)
14417d9bdf4SArnamoy Bhattacharyya           if (const auto &collapseClause =
14517d9bdf4SArnamoy Bhattacharyya                   std::get_if<Fortran::parser::OmpClause::Collapse>(&clause.u))
14617d9bdf4SArnamoy Bhattacharyya             TODO(converter.getCurrentLocation(),
14717d9bdf4SArnamoy Bhattacharyya                  "Collapse clause with lastprivate");
14817d9bdf4SArnamoy Bhattacharyya         // Only generate the compare once in presence of multiple LastPrivate
14917d9bdf4SArnamoy Bhattacharyya         // clauses
15017d9bdf4SArnamoy Bhattacharyya         if (!hasLastPrivateOp) {
15117d9bdf4SArnamoy Bhattacharyya           cmpOp = firOpBuilder.create<mlir::arith::CmpIOp>(
15217d9bdf4SArnamoy Bhattacharyya               wsLoopOp->getLoc(), mlir::arith::CmpIPredicate::eq,
15317d9bdf4SArnamoy Bhattacharyya               wsLoopOp->getRegion().front().getArguments()[0],
15417d9bdf4SArnamoy Bhattacharyya               wsLoopOp->upperBound()[0]);
15517d9bdf4SArnamoy Bhattacharyya         }
15617d9bdf4SArnamoy Bhattacharyya         mlir::scf::IfOp ifOp = firOpBuilder.create<mlir::scf::IfOp>(
15717d9bdf4SArnamoy Bhattacharyya             wsLoopOp->getLoc(), cmpOp, /*else*/ false);
15817d9bdf4SArnamoy Bhattacharyya 
15917d9bdf4SArnamoy Bhattacharyya         firOpBuilder.restoreInsertionPoint(insPt);
16017d9bdf4SArnamoy Bhattacharyya         createPrivateVarSyms(converter, lastPrivateClause,
16117d9bdf4SArnamoy Bhattacharyya                              &(ifOp.getThenRegion().front()));
16217d9bdf4SArnamoy Bhattacharyya       } else {
16317d9bdf4SArnamoy Bhattacharyya         TODO(converter.getCurrentLocation(),
16417d9bdf4SArnamoy Bhattacharyya              "lastprivate clause in constructs other than work-share loop");
16517d9bdf4SArnamoy Bhattacharyya       }
16617d9bdf4SArnamoy Bhattacharyya       hasLastPrivateOp = true;
16707e16a2aSKiran Chandramohan     }
16807e16a2aSKiran Chandramohan   }
169*f2b7f18eSShraiysh Vaishay   if (hasFirstPrivateOp)
170c858f4dbSShraiysh Vaishay     firOpBuilder.create<mlir::omp::BarrierOp>(converter.getCurrentLocation());
17107e16a2aSKiran Chandramohan   firOpBuilder.restoreInsertionPoint(insPt);
17217d9bdf4SArnamoy Bhattacharyya   return hasLastPrivateOp;
17307e16a2aSKiran Chandramohan }
17407e16a2aSKiran Chandramohan 
175411bd2d4SPeixin-Qiao /// The COMMON block is a global structure. \p commonValue is the base address
176411bd2d4SPeixin-Qiao /// of the the COMMON block. As the offset from the symbol \p sym, generate the
177411bd2d4SPeixin-Qiao /// COMMON block member value (commonValue + offset) for the symbol.
178411bd2d4SPeixin-Qiao /// FIXME: Share the code with `instantiateCommon` in ConvertVariable.cpp.
179411bd2d4SPeixin-Qiao static mlir::Value
genCommonBlockMember(Fortran::lower::AbstractConverter & converter,const Fortran::semantics::Symbol & sym,mlir::Value commonValue)180411bd2d4SPeixin-Qiao genCommonBlockMember(Fortran::lower::AbstractConverter &converter,
181411bd2d4SPeixin-Qiao                      const Fortran::semantics::Symbol &sym,
182411bd2d4SPeixin-Qiao                      mlir::Value commonValue) {
183411bd2d4SPeixin-Qiao   auto &firOpBuilder = converter.getFirOpBuilder();
184411bd2d4SPeixin-Qiao   mlir::Location currentLocation = converter.getCurrentLocation();
185411bd2d4SPeixin-Qiao   mlir::IntegerType i8Ty = firOpBuilder.getIntegerType(8);
186411bd2d4SPeixin-Qiao   mlir::Type i8Ptr = firOpBuilder.getRefType(i8Ty);
187411bd2d4SPeixin-Qiao   mlir::Type seqTy = firOpBuilder.getRefType(firOpBuilder.getVarLenSeqTy(i8Ty));
188411bd2d4SPeixin-Qiao   mlir::Value base =
189411bd2d4SPeixin-Qiao       firOpBuilder.createConvert(currentLocation, seqTy, commonValue);
190411bd2d4SPeixin-Qiao   std::size_t byteOffset = sym.GetUltimate().offset();
191411bd2d4SPeixin-Qiao   mlir::Value offs = firOpBuilder.createIntegerConstant(
192411bd2d4SPeixin-Qiao       currentLocation, firOpBuilder.getIndexType(), byteOffset);
193411bd2d4SPeixin-Qiao   mlir::Value varAddr = firOpBuilder.create<fir::CoordinateOp>(
194411bd2d4SPeixin-Qiao       currentLocation, i8Ptr, base, mlir::ValueRange{offs});
195411bd2d4SPeixin-Qiao   mlir::Type symType = converter.genType(sym);
196411bd2d4SPeixin-Qiao   return firOpBuilder.createConvert(currentLocation,
197411bd2d4SPeixin-Qiao                                     firOpBuilder.getRefType(symType), varAddr);
198411bd2d4SPeixin-Qiao }
199411bd2d4SPeixin-Qiao 
200411bd2d4SPeixin-Qiao // Get the extended value for \p val by extracting additional variable
201411bd2d4SPeixin-Qiao // information from \p base.
getExtendedValue(fir::ExtendedValue base,mlir::Value val)202411bd2d4SPeixin-Qiao static fir::ExtendedValue getExtendedValue(fir::ExtendedValue base,
203411bd2d4SPeixin-Qiao                                            mlir::Value val) {
204411bd2d4SPeixin-Qiao   return base.match(
205411bd2d4SPeixin-Qiao       [&](const fir::MutableBoxValue &box) -> fir::ExtendedValue {
206411bd2d4SPeixin-Qiao         return fir::MutableBoxValue(val, box.nonDeferredLenParams(), {});
207411bd2d4SPeixin-Qiao       },
208411bd2d4SPeixin-Qiao       [&](const auto &) -> fir::ExtendedValue {
209411bd2d4SPeixin-Qiao         return fir::substBase(base, val);
210411bd2d4SPeixin-Qiao       });
211411bd2d4SPeixin-Qiao }
212411bd2d4SPeixin-Qiao 
threadPrivatizeVars(Fortran::lower::AbstractConverter & converter,Fortran::lower::pft::Evaluation & eval)213411bd2d4SPeixin-Qiao static void threadPrivatizeVars(Fortran::lower::AbstractConverter &converter,
214411bd2d4SPeixin-Qiao                                 Fortran::lower::pft::Evaluation &eval) {
215411bd2d4SPeixin-Qiao   auto &firOpBuilder = converter.getFirOpBuilder();
216411bd2d4SPeixin-Qiao   mlir::Location currentLocation = converter.getCurrentLocation();
217411bd2d4SPeixin-Qiao   auto insPt = firOpBuilder.saveInsertionPoint();
218411bd2d4SPeixin-Qiao   firOpBuilder.setInsertionPointToStart(firOpBuilder.getAllocaBlock());
219411bd2d4SPeixin-Qiao 
220411bd2d4SPeixin-Qiao   // Get the original ThreadprivateOp corresponding to the symbol and use the
221411bd2d4SPeixin-Qiao   // symbol value from that opeartion to create one ThreadprivateOp copy
222411bd2d4SPeixin-Qiao   // operation inside the parallel region.
223411bd2d4SPeixin-Qiao   auto genThreadprivateOp = [&](Fortran::lower::SymbolRef sym) -> mlir::Value {
224411bd2d4SPeixin-Qiao     mlir::Value symOriThreadprivateValue = converter.getSymbolAddress(sym);
225411bd2d4SPeixin-Qiao     mlir::Operation *op = symOriThreadprivateValue.getDefiningOp();
226411bd2d4SPeixin-Qiao     assert(mlir::isa<mlir::omp::ThreadprivateOp>(op) &&
227411bd2d4SPeixin-Qiao            "The threadprivate operation not created");
228411bd2d4SPeixin-Qiao     mlir::Value symValue =
229411bd2d4SPeixin-Qiao         mlir::dyn_cast<mlir::omp::ThreadprivateOp>(op).sym_addr();
230411bd2d4SPeixin-Qiao     return firOpBuilder.create<mlir::omp::ThreadprivateOp>(
231411bd2d4SPeixin-Qiao         currentLocation, symValue.getType(), symValue);
232411bd2d4SPeixin-Qiao   };
233411bd2d4SPeixin-Qiao 
234411bd2d4SPeixin-Qiao   llvm::SetVector<const Fortran::semantics::Symbol *> threadprivateSyms;
23527afb362SPeixin-Qiao   converter.collectSymbolSet(eval, threadprivateSyms,
23627afb362SPeixin-Qiao                              Fortran::semantics::Symbol::Flag::OmpThreadprivate,
23727afb362SPeixin-Qiao                              /*isUltimateSymbol=*/false);
23827afb362SPeixin-Qiao   std::set<Fortran::semantics::SourceName> threadprivateSymNames;
239411bd2d4SPeixin-Qiao 
240411bd2d4SPeixin-Qiao   // For a COMMON block, the ThreadprivateOp is generated for itself instead of
241411bd2d4SPeixin-Qiao   // its members, so only bind the value of the new copied ThreadprivateOp
242411bd2d4SPeixin-Qiao   // inside the parallel region to the common block symbol only once for
243411bd2d4SPeixin-Qiao   // multiple members in one COMMON block.
244411bd2d4SPeixin-Qiao   llvm::SetVector<const Fortran::semantics::Symbol *> commonSyms;
245411bd2d4SPeixin-Qiao   for (std::size_t i = 0; i < threadprivateSyms.size(); i++) {
246411bd2d4SPeixin-Qiao     auto sym = threadprivateSyms[i];
247411bd2d4SPeixin-Qiao     mlir::Value symThreadprivateValue;
24827afb362SPeixin-Qiao     // The variable may be used more than once, and each reference has one
24927afb362SPeixin-Qiao     // symbol with the same name. Only do once for references of one variable.
25027afb362SPeixin-Qiao     if (threadprivateSymNames.find(sym->name()) != threadprivateSymNames.end())
25127afb362SPeixin-Qiao       continue;
25227afb362SPeixin-Qiao     threadprivateSymNames.insert(sym->name());
253411bd2d4SPeixin-Qiao     if (const Fortran::semantics::Symbol *common =
254411bd2d4SPeixin-Qiao             Fortran::semantics::FindCommonBlockContaining(sym->GetUltimate())) {
255411bd2d4SPeixin-Qiao       mlir::Value commonThreadprivateValue;
256411bd2d4SPeixin-Qiao       if (commonSyms.contains(common)) {
257411bd2d4SPeixin-Qiao         commonThreadprivateValue = converter.getSymbolAddress(*common);
258411bd2d4SPeixin-Qiao       } else {
259411bd2d4SPeixin-Qiao         commonThreadprivateValue = genThreadprivateOp(*common);
260411bd2d4SPeixin-Qiao         converter.bindSymbol(*common, commonThreadprivateValue);
261411bd2d4SPeixin-Qiao         commonSyms.insert(common);
262411bd2d4SPeixin-Qiao       }
263411bd2d4SPeixin-Qiao       symThreadprivateValue =
264411bd2d4SPeixin-Qiao           genCommonBlockMember(converter, *sym, commonThreadprivateValue);
265411bd2d4SPeixin-Qiao     } else {
266411bd2d4SPeixin-Qiao       symThreadprivateValue = genThreadprivateOp(*sym);
267411bd2d4SPeixin-Qiao     }
268411bd2d4SPeixin-Qiao 
269411bd2d4SPeixin-Qiao     fir::ExtendedValue sexv = converter.getSymbolExtendedValue(*sym);
270411bd2d4SPeixin-Qiao     fir::ExtendedValue symThreadprivateExv =
271411bd2d4SPeixin-Qiao         getExtendedValue(sexv, symThreadprivateValue);
272411bd2d4SPeixin-Qiao     converter.bindSymbol(*sym, symThreadprivateExv);
273411bd2d4SPeixin-Qiao   }
274411bd2d4SPeixin-Qiao 
275411bd2d4SPeixin-Qiao   firOpBuilder.restoreInsertionPoint(insPt);
276411bd2d4SPeixin-Qiao }
277411bd2d4SPeixin-Qiao 
27827afb362SPeixin-Qiao static void
genCopyinClause(Fortran::lower::AbstractConverter & converter,const Fortran::parser::OmpClauseList & opClauseList)27927afb362SPeixin-Qiao genCopyinClause(Fortran::lower::AbstractConverter &converter,
28027afb362SPeixin-Qiao                 const Fortran::parser::OmpClauseList &opClauseList) {
28127afb362SPeixin-Qiao   fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();
28227afb362SPeixin-Qiao   mlir::OpBuilder::InsertPoint insPt = firOpBuilder.saveInsertionPoint();
28327afb362SPeixin-Qiao   firOpBuilder.setInsertionPointToStart(firOpBuilder.getAllocaBlock());
28427afb362SPeixin-Qiao   bool hasCopyin = false;
28527afb362SPeixin-Qiao   for (const Fortran::parser::OmpClause &clause : opClauseList.v) {
28627afb362SPeixin-Qiao     if (const auto &copyinClause =
28727afb362SPeixin-Qiao             std::get_if<Fortran::parser::OmpClause::Copyin>(&clause.u)) {
28827afb362SPeixin-Qiao       hasCopyin = true;
28927afb362SPeixin-Qiao       const Fortran::parser::OmpObjectList &ompObjectList = copyinClause->v;
29027afb362SPeixin-Qiao       for (const Fortran::parser::OmpObject &ompObject : ompObjectList.v) {
29127afb362SPeixin-Qiao         Fortran::semantics::Symbol *sym = getOmpObjectSymbol(ompObject);
29227afb362SPeixin-Qiao         if (sym->has<Fortran::semantics::CommonBlockDetails>())
29327afb362SPeixin-Qiao           TODO(converter.getCurrentLocation(), "common block in Copyin clause");
29427afb362SPeixin-Qiao         if (Fortran::semantics::IsAllocatableOrPointer(sym->GetUltimate()))
29527afb362SPeixin-Qiao           TODO(converter.getCurrentLocation(),
29627afb362SPeixin-Qiao                "pointer or allocatable variables in Copyin clause");
29727afb362SPeixin-Qiao         assert(sym->has<Fortran::semantics::HostAssocDetails>() &&
29827afb362SPeixin-Qiao                "No host-association found");
29927afb362SPeixin-Qiao         converter.copyHostAssociateVar(*sym);
30027afb362SPeixin-Qiao       }
30127afb362SPeixin-Qiao     }
30227afb362SPeixin-Qiao   }
30313019955SPeixin Qiao   // [OMP 5.0, 2.19.6.1] The copy is done after the team is formed and prior to
30413019955SPeixin Qiao   // the execution of the associated structured block. Emit implicit barrier to
30513019955SPeixin Qiao   // synchronize threads and avoid data races on propagation master's thread
30613019955SPeixin Qiao   // values of threadprivate variables to local instances of that variables of
30713019955SPeixin Qiao   // all other implicit threads.
30827afb362SPeixin-Qiao   if (hasCopyin)
30927afb362SPeixin-Qiao     firOpBuilder.create<mlir::omp::BarrierOp>(converter.getCurrentLocation());
31027afb362SPeixin-Qiao   firOpBuilder.restoreInsertionPoint(insPt);
31127afb362SPeixin-Qiao }
31227afb362SPeixin-Qiao 
genObjectList(const Fortran::parser::OmpObjectList & objectList,Fortran::lower::AbstractConverter & converter,llvm::SmallVectorImpl<Value> & operands)31307e16a2aSKiran Chandramohan static void genObjectList(const Fortran::parser::OmpObjectList &objectList,
31407e16a2aSKiran Chandramohan                           Fortran::lower::AbstractConverter &converter,
31507e16a2aSKiran Chandramohan                           llvm::SmallVectorImpl<Value> &operands) {
31607e16a2aSKiran Chandramohan   auto addOperands = [&](Fortran::lower::SymbolRef sym) {
31707e16a2aSKiran Chandramohan     const mlir::Value variable = converter.getSymbolAddress(sym);
31807e16a2aSKiran Chandramohan     if (variable) {
3191d328446SSourabh Singh Tomar       operands.push_back(variable);
32007e16a2aSKiran Chandramohan     } else {
32107e16a2aSKiran Chandramohan       if (const auto *details =
32207e16a2aSKiran Chandramohan               sym->detailsIf<Fortran::semantics::HostAssocDetails>()) {
32307e16a2aSKiran Chandramohan         operands.push_back(converter.getSymbolAddress(details->symbol()));
32407e16a2aSKiran Chandramohan         converter.copySymbolBinding(details->symbol(), sym);
32507e16a2aSKiran Chandramohan       }
32607e16a2aSKiran Chandramohan     }
32707e16a2aSKiran Chandramohan   };
32807e16a2aSKiran Chandramohan   for (const Fortran::parser::OmpObject &ompObject : objectList.v) {
329bc99d565SPeixinQiao     Fortran::semantics::Symbol *sym = getOmpObjectSymbol(ompObject);
330bc99d565SPeixinQiao     addOperands(*sym);
3311d328446SSourabh Singh Tomar   }
3321d328446SSourabh Singh Tomar }
3331d328446SSourabh Singh Tomar 
getLoopVarType(Fortran::lower::AbstractConverter & converter,std::size_t loopVarTypeSize)334870f4421SPeixin-Qiao static mlir::Type getLoopVarType(Fortran::lower::AbstractConverter &converter,
335870f4421SPeixin-Qiao                                  std::size_t loopVarTypeSize) {
336870f4421SPeixin-Qiao   // OpenMP runtime requires 32-bit or 64-bit loop variables.
337870f4421SPeixin-Qiao   loopVarTypeSize = loopVarTypeSize * 8;
338870f4421SPeixin-Qiao   if (loopVarTypeSize < 32) {
339870f4421SPeixin-Qiao     loopVarTypeSize = 32;
340870f4421SPeixin-Qiao   } else if (loopVarTypeSize > 64) {
341870f4421SPeixin-Qiao     loopVarTypeSize = 64;
342870f4421SPeixin-Qiao     mlir::emitWarning(converter.getCurrentLocation(),
343870f4421SPeixin-Qiao                       "OpenMP loop iteration variable cannot have more than 64 "
344870f4421SPeixin-Qiao                       "bits size and will be narrowed into 64 bits.");
345870f4421SPeixin-Qiao   }
346870f4421SPeixin-Qiao   assert((loopVarTypeSize == 32 || loopVarTypeSize == 64) &&
347870f4421SPeixin-Qiao          "OpenMP loop iteration variable size must be transformed into 32-bit "
348870f4421SPeixin-Qiao          "or 64-bit");
349870f4421SPeixin-Qiao   return converter.getFirOpBuilder().getIntegerType(loopVarTypeSize);
350870f4421SPeixin-Qiao }
351870f4421SPeixin-Qiao 
35229f167abSKiran Chandramohan /// Create empty blocks for the current region.
35329f167abSKiran Chandramohan /// These blocks replace blocks parented to an enclosing region.
createEmptyRegionBlocks(fir::FirOpBuilder & firOpBuilder,std::list<Fortran::lower::pft::Evaluation> & evaluationList)35429f167abSKiran Chandramohan void createEmptyRegionBlocks(
35529f167abSKiran Chandramohan     fir::FirOpBuilder &firOpBuilder,
35629f167abSKiran Chandramohan     std::list<Fortran::lower::pft::Evaluation> &evaluationList) {
35729f167abSKiran Chandramohan   auto *region = &firOpBuilder.getRegion();
35829f167abSKiran Chandramohan   for (auto &eval : evaluationList) {
35929f167abSKiran Chandramohan     if (eval.block) {
36029f167abSKiran Chandramohan       if (eval.block->empty()) {
36129f167abSKiran Chandramohan         eval.block->erase();
36229f167abSKiran Chandramohan         eval.block = firOpBuilder.createBlock(region);
36329f167abSKiran Chandramohan       } else {
36429f167abSKiran Chandramohan         [[maybe_unused]] auto &terminatorOp = eval.block->back();
36529f167abSKiran Chandramohan         assert((mlir::isa<mlir::omp::TerminatorOp>(terminatorOp) ||
36629f167abSKiran Chandramohan                 mlir::isa<mlir::omp::YieldOp>(terminatorOp)) &&
36729f167abSKiran Chandramohan                "expected terminator op");
36829f167abSKiran Chandramohan       }
36929f167abSKiran Chandramohan     }
370b501503cSkiranchandramohan     if (!eval.isDirective() && eval.hasNestedEvaluations())
37129f167abSKiran Chandramohan       createEmptyRegionBlocks(firOpBuilder, eval.getNestedEvaluations());
37229f167abSKiran Chandramohan   }
37329f167abSKiran Chandramohan }
37429f167abSKiran Chandramohan 
resetBeforeTerminator(fir::FirOpBuilder & firOpBuilder,mlir::Operation * storeOp,mlir::Block & block)37517d9bdf4SArnamoy Bhattacharyya void resetBeforeTerminator(fir::FirOpBuilder &firOpBuilder,
37617d9bdf4SArnamoy Bhattacharyya                            mlir::Operation *storeOp, mlir::Block &block) {
37717d9bdf4SArnamoy Bhattacharyya   if (storeOp)
37817d9bdf4SArnamoy Bhattacharyya     firOpBuilder.setInsertionPointAfter(storeOp);
37917d9bdf4SArnamoy Bhattacharyya   else
38017d9bdf4SArnamoy Bhattacharyya     firOpBuilder.setInsertionPointToStart(&block);
38117d9bdf4SArnamoy Bhattacharyya }
38217d9bdf4SArnamoy Bhattacharyya 
3833b390a16SMats Petersson /// Create the body (block) for an OpenMP Operation.
3843b390a16SMats Petersson ///
3853b390a16SMats Petersson /// \param [in]    op - the operation the body belongs to.
3863b390a16SMats Petersson /// \param [inout] converter - converter to use for the clauses.
3873b390a16SMats Petersson /// \param [in]    loc - location in source code.
38829f167abSKiran Chandramohan /// \param [in]    eval - current PFT node/evaluation.
3893b390a16SMats Petersson /// \oaran [in]    clauses - list of clauses to process.
3903b390a16SMats Petersson /// \param [in]    args - block arguments (induction variable[s]) for the
3913b390a16SMats Petersson ////                      region.
3923b390a16SMats Petersson /// \param [in]    outerCombined - is this an outer operation - prevents
3933b390a16SMats Petersson ///                                privatization.
3941d328446SSourabh Singh Tomar template <typename Op>
39507e16a2aSKiran Chandramohan static void
createBodyOfOp(Op & op,Fortran::lower::AbstractConverter & converter,mlir::Location & loc,Fortran::lower::pft::Evaluation & eval,const Fortran::parser::OmpClauseList * clauses=nullptr,const SmallVector<const Fortran::semantics::Symbol * > & args={},bool outerCombined=false)39607e16a2aSKiran Chandramohan createBodyOfOp(Op &op, Fortran::lower::AbstractConverter &converter,
39729f167abSKiran Chandramohan                mlir::Location &loc, Fortran::lower::pft::Evaluation &eval,
39807e16a2aSKiran Chandramohan                const Fortran::parser::OmpClauseList *clauses = nullptr,
3993b390a16SMats Petersson                const SmallVector<const Fortran::semantics::Symbol *> &args = {},
40007e16a2aSKiran Chandramohan                bool outerCombined = false) {
401b501503cSkiranchandramohan   fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();
40229f167abSKiran Chandramohan   // If an argument for the region is provided then create the block with that
40329f167abSKiran Chandramohan   // argument. Also update the symbol's address with the mlir argument value.
40429f167abSKiran Chandramohan   // e.g. For loops the argument is the induction variable. And all further
405b85c39ddSKiran Chandramohan   // uses of the induction variable should use this mlir value.
406dc4bf2c3SMats Petersson   mlir::Operation *storeOp = nullptr;
4073b390a16SMats Petersson   if (args.size()) {
408870f4421SPeixin-Qiao     std::size_t loopVarTypeSize = 0;
409870f4421SPeixin-Qiao     for (const Fortran::semantics::Symbol *arg : args)
410870f4421SPeixin-Qiao       loopVarTypeSize = std::max(loopVarTypeSize, arg->GetUltimate().size());
411870f4421SPeixin-Qiao     mlir::Type loopVarType = getLoopVarType(converter, loopVarTypeSize);
4123b390a16SMats Petersson     SmallVector<Type> tiv;
4133b390a16SMats Petersson     SmallVector<Location> locs;
414870f4421SPeixin-Qiao     for (int i = 0; i < (int)args.size(); i++) {
415870f4421SPeixin-Qiao       tiv.push_back(loopVarType);
4163b390a16SMats Petersson       locs.push_back(loc);
4173b390a16SMats Petersson     }
4183b390a16SMats Petersson     firOpBuilder.createBlock(&op.getRegion(), {}, tiv, locs);
419870f4421SPeixin-Qiao     int argIndex = 0;
420dc4bf2c3SMats Petersson     // The argument is not currently in memory, so make a temporary for the
421dc4bf2c3SMats Petersson     // argument, and store it there, then bind that location to the argument.
422870f4421SPeixin-Qiao     for (const Fortran::semantics::Symbol *arg : args) {
423dc4bf2c3SMats Petersson       mlir::Value val =
424dc4bf2c3SMats Petersson           fir::getBase(op.getRegion().front().getArgument(argIndex));
425dc4bf2c3SMats Petersson       mlir::Value temp = firOpBuilder.createTemporary(
426dc4bf2c3SMats Petersson           loc, loopVarType,
427dc4bf2c3SMats Petersson           llvm::ArrayRef<mlir::NamedAttribute>{
428dc4bf2c3SMats Petersson               Fortran::lower::getAdaptToByRefAttr(firOpBuilder)});
429dc4bf2c3SMats Petersson       storeOp = firOpBuilder.create<fir::StoreOp>(loc, val, temp);
430dc4bf2c3SMats Petersson       converter.bindSymbol(*arg, temp);
4313b390a16SMats Petersson       argIndex++;
4323b390a16SMats Petersson     }
433b85c39ddSKiran Chandramohan   } else {
4341d328446SSourabh Singh Tomar     firOpBuilder.createBlock(&op.getRegion());
435b85c39ddSKiran Chandramohan   }
436dc4bf2c3SMats Petersson   // Set the insert for the terminator operation to go at the end of the
437dc4bf2c3SMats Petersson   // block - this is either empty or the block with the stores above,
438dc4bf2c3SMats Petersson   // the end of the block works for both.
439b501503cSkiranchandramohan   mlir::Block &block = op.getRegion().back();
440b501503cSkiranchandramohan   firOpBuilder.setInsertionPointToEnd(&block);
441b85c39ddSKiran Chandramohan 
442b501503cSkiranchandramohan   // If it is an unstructured region and is not the outer region of a combined
443b501503cSkiranchandramohan   // construct, create empty blocks for all evaluations.
444b501503cSkiranchandramohan   if (eval.lowerAsUnstructured() && !outerCombined)
44529f167abSKiran Chandramohan     createEmptyRegionBlocks(firOpBuilder, eval.getNestedEvaluations());
44629f167abSKiran Chandramohan 
447b501503cSkiranchandramohan   // Insert the terminator.
4483f4a63e5SArnamoy Bhattacharyya   if constexpr (std::is_same_v<Op, omp::WsLoopOp> ||
4493f4a63e5SArnamoy Bhattacharyya                 std::is_same_v<Op, omp::SimdLoopOp>) {
450b85c39ddSKiran Chandramohan     mlir::ValueRange results;
451b85c39ddSKiran Chandramohan     firOpBuilder.create<mlir::omp::YieldOp>(loc, results);
452b85c39ddSKiran Chandramohan   } else {
4531d328446SSourabh Singh Tomar     firOpBuilder.create<mlir::omp::TerminatorOp>(loc);
454b85c39ddSKiran Chandramohan   }
455b85c39ddSKiran Chandramohan 
456dc4bf2c3SMats Petersson   // Reset the insert point to before the terminator.
45717d9bdf4SArnamoy Bhattacharyya   resetBeforeTerminator(firOpBuilder, storeOp, block);
458b501503cSkiranchandramohan 
45907e16a2aSKiran Chandramohan   // Handle privatization. Do not privatize if this is the outer operation.
46017d9bdf4SArnamoy Bhattacharyya   if (clauses && !outerCombined) {
461*f2b7f18eSShraiysh Vaishay     bool lastPrivateOp = privatizeVars(op, converter, *clauses);
46217d9bdf4SArnamoy Bhattacharyya     // LastPrivatization, due to introduction of
46317d9bdf4SArnamoy Bhattacharyya     // new control flow, changes the insertion point,
46417d9bdf4SArnamoy Bhattacharyya     // thus restore it.
46517d9bdf4SArnamoy Bhattacharyya     // TODO: Clean up later a bit to avoid this many sets and resets.
46617d9bdf4SArnamoy Bhattacharyya     if (lastPrivateOp)
46717d9bdf4SArnamoy Bhattacharyya       resetBeforeTerminator(firOpBuilder, storeOp, block);
46817d9bdf4SArnamoy Bhattacharyya   }
469411bd2d4SPeixin-Qiao 
470794b3bf7SPeixin-Qiao   if constexpr (std::is_same_v<Op, omp::ParallelOp>) {
471411bd2d4SPeixin-Qiao     threadPrivatizeVars(converter, eval);
47227afb362SPeixin-Qiao     if (clauses)
47327afb362SPeixin-Qiao       genCopyinClause(converter, *clauses);
47427afb362SPeixin-Qiao   }
4751d328446SSourabh Singh Tomar }
476ae6e499dSEric Schweitz 
genOMP(Fortran::lower::AbstractConverter & converter,Fortran::lower::pft::Evaluation & eval,const Fortran::parser::OpenMPSimpleStandaloneConstruct & simpleStandaloneConstruct)477dfa9065aSSourabh Singh Tomar static void genOMP(Fortran::lower::AbstractConverter &converter,
4783d0b7602SSourabh Singh Tomar                    Fortran::lower::pft::Evaluation &eval,
4793d0b7602SSourabh Singh Tomar                    const Fortran::parser::OpenMPSimpleStandaloneConstruct
4803d0b7602SSourabh Singh Tomar                        &simpleStandaloneConstruct) {
4813d0b7602SSourabh Singh Tomar   const auto &directive =
4823d0b7602SSourabh Singh Tomar       std::get<Fortran::parser::OmpSimpleStandaloneDirective>(
4833d0b7602SSourabh Singh Tomar           simpleStandaloneConstruct.t);
4843d0b7602SSourabh Singh Tomar   switch (directive.v) {
4853d0b7602SSourabh Singh Tomar   default:
4863d0b7602SSourabh Singh Tomar     break;
4873d0b7602SSourabh Singh Tomar   case llvm::omp::Directive::OMPD_barrier:
488dfa9065aSSourabh Singh Tomar     converter.getFirOpBuilder().create<mlir::omp::BarrierOp>(
489dfa9065aSSourabh Singh Tomar         converter.getCurrentLocation());
4903d0b7602SSourabh Singh Tomar     break;
4913d0b7602SSourabh Singh Tomar   case llvm::omp::Directive::OMPD_taskwait:
492dfa9065aSSourabh Singh Tomar     converter.getFirOpBuilder().create<mlir::omp::TaskwaitOp>(
493dfa9065aSSourabh Singh Tomar         converter.getCurrentLocation());
494079b49b3SSourabh Singh Tomar     break;
4953d0b7602SSourabh Singh Tomar   case llvm::omp::Directive::OMPD_taskyield:
496dfa9065aSSourabh Singh Tomar     converter.getFirOpBuilder().create<mlir::omp::TaskyieldOp>(
497dfa9065aSSourabh Singh Tomar         converter.getCurrentLocation());
4989e4ab439SSourabh Singh Tomar     break;
4993d0b7602SSourabh Singh Tomar   case llvm::omp::Directive::OMPD_target_enter_data:
50036ea1cacSJean Perier     TODO(converter.getCurrentLocation(), "OMPD_target_enter_data");
5013d0b7602SSourabh Singh Tomar   case llvm::omp::Directive::OMPD_target_exit_data:
50236ea1cacSJean Perier     TODO(converter.getCurrentLocation(), "OMPD_target_exit_data");
5033d0b7602SSourabh Singh Tomar   case llvm::omp::Directive::OMPD_target_update:
50436ea1cacSJean Perier     TODO(converter.getCurrentLocation(), "OMPD_target_update");
5053d0b7602SSourabh Singh Tomar   case llvm::omp::Directive::OMPD_ordered:
50636ea1cacSJean Perier     TODO(converter.getCurrentLocation(), "OMPD_ordered");
5073d0b7602SSourabh Singh Tomar   }
5083d0b7602SSourabh Singh Tomar }
5093d0b7602SSourabh Singh Tomar 
5103d0b7602SSourabh Singh Tomar static void
genAllocateClause(Fortran::lower::AbstractConverter & converter,const Fortran::parser::OmpAllocateClause & ompAllocateClause,SmallVector<Value> & allocatorOperands,SmallVector<Value> & allocateOperands)51188d5289fSNimish Mishra genAllocateClause(Fortran::lower::AbstractConverter &converter,
51288d5289fSNimish Mishra                   const Fortran::parser::OmpAllocateClause &ompAllocateClause,
51388d5289fSNimish Mishra                   SmallVector<Value> &allocatorOperands,
51488d5289fSNimish Mishra                   SmallVector<Value> &allocateOperands) {
51588d5289fSNimish Mishra   auto &firOpBuilder = converter.getFirOpBuilder();
51688d5289fSNimish Mishra   auto currentLocation = converter.getCurrentLocation();
51788d5289fSNimish Mishra   Fortran::lower::StatementContext stmtCtx;
51888d5289fSNimish Mishra 
51988d5289fSNimish Mishra   mlir::Value allocatorOperand;
52088d5289fSNimish Mishra   const Fortran::parser::OmpObjectList &ompObjectList =
52188d5289fSNimish Mishra       std::get<Fortran::parser::OmpObjectList>(ompAllocateClause.t);
52288d5289fSNimish Mishra   const auto &allocatorValue =
52388d5289fSNimish Mishra       std::get<std::optional<Fortran::parser::OmpAllocateClause::Allocator>>(
52488d5289fSNimish Mishra           ompAllocateClause.t);
52588d5289fSNimish Mishra   // Check if allocate clause has allocator specified. If so, add it
52688d5289fSNimish Mishra   // to list of allocators, otherwise, add default allocator to
52788d5289fSNimish Mishra   // list of allocators.
52888d5289fSNimish Mishra   if (allocatorValue) {
52988d5289fSNimish Mishra     allocatorOperand = fir::getBase(converter.genExprValue(
53088d5289fSNimish Mishra         *Fortran::semantics::GetExpr(allocatorValue->v), stmtCtx));
53188d5289fSNimish Mishra     allocatorOperands.insert(allocatorOperands.end(), ompObjectList.v.size(),
53288d5289fSNimish Mishra                              allocatorOperand);
53388d5289fSNimish Mishra   } else {
53488d5289fSNimish Mishra     allocatorOperand = firOpBuilder.createIntegerConstant(
53588d5289fSNimish Mishra         currentLocation, firOpBuilder.getI32Type(), 1);
53688d5289fSNimish Mishra     allocatorOperands.insert(allocatorOperands.end(), ompObjectList.v.size(),
53788d5289fSNimish Mishra                              allocatorOperand);
53888d5289fSNimish Mishra   }
53988d5289fSNimish Mishra   genObjectList(ompObjectList, converter, allocateOperands);
54088d5289fSNimish Mishra }
54188d5289fSNimish Mishra 
54288d5289fSNimish Mishra static void
genOMP(Fortran::lower::AbstractConverter & converter,Fortran::lower::pft::Evaluation & eval,const Fortran::parser::OpenMPStandaloneConstruct & standaloneConstruct)543dfa9065aSSourabh Singh Tomar genOMP(Fortran::lower::AbstractConverter &converter,
5443d0b7602SSourabh Singh Tomar        Fortran::lower::pft::Evaluation &eval,
5453d0b7602SSourabh Singh Tomar        const Fortran::parser::OpenMPStandaloneConstruct &standaloneConstruct) {
5463d0b7602SSourabh Singh Tomar   std::visit(
5473d0b7602SSourabh Singh Tomar       Fortran::common::visitors{
5483d0b7602SSourabh Singh Tomar           [&](const Fortran::parser::OpenMPSimpleStandaloneConstruct
5493d0b7602SSourabh Singh Tomar                   &simpleStandaloneConstruct) {
550dfa9065aSSourabh Singh Tomar             genOMP(converter, eval, simpleStandaloneConstruct);
5513d0b7602SSourabh Singh Tomar           },
5523d0b7602SSourabh Singh Tomar           [&](const Fortran::parser::OpenMPFlushConstruct &flushConstruct) {
553e7d37742SSourabh Singh Tomar             SmallVector<Value, 4> operandRange;
554e7d37742SSourabh Singh Tomar             if (const auto &ompObjectList =
555e7d37742SSourabh Singh Tomar                     std::get<std::optional<Fortran::parser::OmpObjectList>>(
556e7d37742SSourabh Singh Tomar                         flushConstruct.t))
557e7d37742SSourabh Singh Tomar               genObjectList(*ompObjectList, converter, operandRange);
55851433662SShraiysh Vaishay             const auto &memOrderClause = std::get<std::optional<
559f1569b1eSsameeran joshi                 std::list<Fortran::parser::OmpMemoryOrderClause>>>(
56051433662SShraiysh Vaishay                 flushConstruct.t);
56151433662SShraiysh Vaishay             if (memOrderClause.has_value() && memOrderClause->size() > 0)
56236ea1cacSJean Perier               TODO(converter.getCurrentLocation(),
56336ea1cacSJean Perier                    "Handle OmpMemoryOrderClause");
564e7d37742SSourabh Singh Tomar             converter.getFirOpBuilder().create<mlir::omp::FlushOp>(
565e7d37742SSourabh Singh Tomar                 converter.getCurrentLocation(), operandRange);
5663d0b7602SSourabh Singh Tomar           },
5673d0b7602SSourabh Singh Tomar           [&](const Fortran::parser::OpenMPCancelConstruct &cancelConstruct) {
56836ea1cacSJean Perier             TODO(converter.getCurrentLocation(), "OpenMPCancelConstruct");
5693d0b7602SSourabh Singh Tomar           },
5703d0b7602SSourabh Singh Tomar           [&](const Fortran::parser::OpenMPCancellationPointConstruct
57136ea1cacSJean Perier                   &cancellationPointConstruct) {
57236ea1cacSJean Perier             TODO(converter.getCurrentLocation(), "OpenMPCancelConstruct");
57336ea1cacSJean Perier           },
5743d0b7602SSourabh Singh Tomar       },
5753d0b7602SSourabh Singh Tomar       standaloneConstruct.u);
5763d0b7602SSourabh Singh Tomar }
5773d0b7602SSourabh Singh Tomar 
genProcBindKindAttr(fir::FirOpBuilder & firOpBuilder,const Fortran::parser::OmpClause::ProcBind * procBindClause)5784202d69dSKiran Chandramohan static omp::ClauseProcBindKindAttr genProcBindKindAttr(
5794202d69dSKiran Chandramohan     fir::FirOpBuilder &firOpBuilder,
5804202d69dSKiran Chandramohan     const Fortran::parser::OmpClause::ProcBind *procBindClause) {
5814202d69dSKiran Chandramohan   omp::ClauseProcBindKind pbKind;
5824202d69dSKiran Chandramohan   switch (procBindClause->v.v) {
5834202d69dSKiran Chandramohan   case Fortran::parser::OmpProcBindClause::Type::Master:
5844202d69dSKiran Chandramohan     pbKind = omp::ClauseProcBindKind::Master;
5854202d69dSKiran Chandramohan     break;
5864202d69dSKiran Chandramohan   case Fortran::parser::OmpProcBindClause::Type::Close:
5874202d69dSKiran Chandramohan     pbKind = omp::ClauseProcBindKind::Close;
5884202d69dSKiran Chandramohan     break;
5894202d69dSKiran Chandramohan   case Fortran::parser::OmpProcBindClause::Type::Spread:
5904202d69dSKiran Chandramohan     pbKind = omp::ClauseProcBindKind::Spread;
5914202d69dSKiran Chandramohan     break;
5924202d69dSKiran Chandramohan   case Fortran::parser::OmpProcBindClause::Type::Primary:
5934202d69dSKiran Chandramohan     pbKind = omp::ClauseProcBindKind::Primary;
5944202d69dSKiran Chandramohan     break;
5954202d69dSKiran Chandramohan   }
5964202d69dSKiran Chandramohan   return omp::ClauseProcBindKindAttr::get(firOpBuilder.getContext(), pbKind);
5974202d69dSKiran Chandramohan }
5984202d69dSKiran Chandramohan 
5992c915e3bSDominik Adamski static mlir::Value
getIfClauseOperand(Fortran::lower::AbstractConverter & converter,Fortran::lower::StatementContext & stmtCtx,const Fortran::parser::OmpClause::If * ifClause)6002c915e3bSDominik Adamski getIfClauseOperand(Fortran::lower::AbstractConverter &converter,
6012c915e3bSDominik Adamski                    Fortran::lower::StatementContext &stmtCtx,
6022c915e3bSDominik Adamski                    const Fortran::parser::OmpClause::If *ifClause) {
6032c915e3bSDominik Adamski   fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();
6042c915e3bSDominik Adamski   mlir::Location currentLocation = converter.getCurrentLocation();
6052c915e3bSDominik Adamski   auto &expr = std::get<Fortran::parser::ScalarLogicalExpr>(ifClause->v.t);
6062c915e3bSDominik Adamski   mlir::Value ifVal = fir::getBase(
6072c915e3bSDominik Adamski       converter.genExprValue(*Fortran::semantics::GetExpr(expr), stmtCtx));
6082c915e3bSDominik Adamski   return firOpBuilder.createConvert(currentLocation, firOpBuilder.getI1Type(),
6092c915e3bSDominik Adamski                                     ifVal);
6102c915e3bSDominik Adamski }
6112c915e3bSDominik Adamski 
6124202d69dSKiran Chandramohan /* When parallel is used in a combined construct, then use this function to
6134202d69dSKiran Chandramohan  * create the parallel operation. It handles the parallel specific clauses
6144202d69dSKiran Chandramohan  * and leaves the rest for handling at the inner operations.
6154202d69dSKiran Chandramohan  * TODO: Refactor clause handling
6164202d69dSKiran Chandramohan  */
6174202d69dSKiran Chandramohan template <typename Directive>
6184202d69dSKiran Chandramohan static void
createCombinedParallelOp(Fortran::lower::AbstractConverter & converter,Fortran::lower::pft::Evaluation & eval,const Directive & directive)6194202d69dSKiran Chandramohan createCombinedParallelOp(Fortran::lower::AbstractConverter &converter,
6204202d69dSKiran Chandramohan                          Fortran::lower::pft::Evaluation &eval,
6214202d69dSKiran Chandramohan                          const Directive &directive) {
6224202d69dSKiran Chandramohan   fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();
6234202d69dSKiran Chandramohan   mlir::Location currentLocation = converter.getCurrentLocation();
6244202d69dSKiran Chandramohan   Fortran::lower::StatementContext stmtCtx;
6254202d69dSKiran Chandramohan   llvm::ArrayRef<mlir::Type> argTy;
6264202d69dSKiran Chandramohan   mlir::Value ifClauseOperand, numThreadsClauseOperand;
6274202d69dSKiran Chandramohan   SmallVector<Value> allocatorOperands, allocateOperands;
6284202d69dSKiran Chandramohan   mlir::omp::ClauseProcBindKindAttr procBindKindAttr;
6294202d69dSKiran Chandramohan   const auto &opClauseList =
6304202d69dSKiran Chandramohan       std::get<Fortran::parser::OmpClauseList>(directive.t);
6314202d69dSKiran Chandramohan   // TODO: Handle the following clauses
6324202d69dSKiran Chandramohan   // 1. default
6334202d69dSKiran Chandramohan   // Note: rest of the clauses are handled when the inner operation is created
6344202d69dSKiran Chandramohan   for (const Fortran::parser::OmpClause &clause : opClauseList.v) {
6354202d69dSKiran Chandramohan     if (const auto &ifClause =
6364202d69dSKiran Chandramohan             std::get_if<Fortran::parser::OmpClause::If>(&clause.u)) {
6372c915e3bSDominik Adamski       ifClauseOperand = getIfClauseOperand(converter, stmtCtx, ifClause);
6384202d69dSKiran Chandramohan     } else if (const auto &numThreadsClause =
6394202d69dSKiran Chandramohan                    std::get_if<Fortran::parser::OmpClause::NumThreads>(
6404202d69dSKiran Chandramohan                        &clause.u)) {
6414202d69dSKiran Chandramohan       numThreadsClauseOperand = fir::getBase(converter.genExprValue(
6424202d69dSKiran Chandramohan           *Fortran::semantics::GetExpr(numThreadsClause->v), stmtCtx));
6434202d69dSKiran Chandramohan     } else if (const auto &procBindClause =
6444202d69dSKiran Chandramohan                    std::get_if<Fortran::parser::OmpClause::ProcBind>(
6454202d69dSKiran Chandramohan                        &clause.u)) {
6464202d69dSKiran Chandramohan       procBindKindAttr = genProcBindKindAttr(firOpBuilder, procBindClause);
6474202d69dSKiran Chandramohan     }
6484202d69dSKiran Chandramohan   }
6494202d69dSKiran Chandramohan   // Create and insert the operation.
6504202d69dSKiran Chandramohan   auto parallelOp = firOpBuilder.create<mlir::omp::ParallelOp>(
6514202d69dSKiran Chandramohan       currentLocation, argTy, ifClauseOperand, numThreadsClauseOperand,
6524202d69dSKiran Chandramohan       allocateOperands, allocatorOperands, /*reduction_vars=*/ValueRange(),
6534202d69dSKiran Chandramohan       /*reductions=*/nullptr, procBindKindAttr);
6544202d69dSKiran Chandramohan 
65529f167abSKiran Chandramohan   createBodyOfOp<omp::ParallelOp>(parallelOp, converter, currentLocation, eval,
6564202d69dSKiran Chandramohan                                   &opClauseList, /*iv=*/{},
6574202d69dSKiran Chandramohan                                   /*isCombined=*/true);
6584202d69dSKiran Chandramohan }
6594202d69dSKiran Chandramohan 
660bf812c14SSourabh Singh Tomar static void
genOMP(Fortran::lower::AbstractConverter & converter,Fortran::lower::pft::Evaluation & eval,const Fortran::parser::OpenMPBlockConstruct & blockConstruct)661dfa9065aSSourabh Singh Tomar genOMP(Fortran::lower::AbstractConverter &converter,
662bf812c14SSourabh Singh Tomar        Fortran::lower::pft::Evaluation &eval,
663bf812c14SSourabh Singh Tomar        const Fortran::parser::OpenMPBlockConstruct &blockConstruct) {
6641d328446SSourabh Singh Tomar   const auto &beginBlockDirective =
665bf812c14SSourabh Singh Tomar       std::get<Fortran::parser::OmpBeginBlockDirective>(blockConstruct.t);
6661d328446SSourabh Singh Tomar   const auto &blockDirective =
6671d328446SSourabh Singh Tomar       std::get<Fortran::parser::OmpBlockDirective>(beginBlockDirective.t);
668cd28353eSShraiysh Vaishay   const auto &endBlockDirective =
669cd28353eSShraiysh Vaishay       std::get<Fortran::parser::OmpEndBlockDirective>(blockConstruct.t);
67007e16a2aSKiran Chandramohan   fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();
67107e16a2aSKiran Chandramohan   mlir::Location currentLocation = converter.getCurrentLocation();
6721d328446SSourabh Singh Tomar 
673d0b70a07SValentin Clement   Fortran::lower::StatementContext stmtCtx;
6741d328446SSourabh Singh Tomar   llvm::ArrayRef<mlir::Type> argTy;
67504cb01cfSShraiysh Vaishay   mlir::Value ifClauseOperand, numThreadsClauseOperand, finalClauseOperand,
67604cb01cfSShraiysh Vaishay       priorityClauseOperand;
677fa4b1e1eSShraiysh Vaishay   mlir::omp::ClauseProcBindKindAttr procBindKindAttr;
678fa4b1e1eSShraiysh Vaishay   SmallVector<Value> allocateOperands, allocatorOperands;
67904cb01cfSShraiysh Vaishay   mlir::UnitAttr nowaitAttr, untiedAttr, mergeableAttr;
68034b08487SSourabh Singh Tomar 
68107e16a2aSKiran Chandramohan   const auto &opClauseList =
68207e16a2aSKiran Chandramohan       std::get<Fortran::parser::OmpClauseList>(beginBlockDirective.t);
68307e16a2aSKiran Chandramohan   for (const auto &clause : opClauseList.v) {
6841d328446SSourabh Singh Tomar     if (const auto &ifClause =
6856bd0a445SValentin Clement             std::get_if<Fortran::parser::OmpClause::If>(&clause.u)) {
6862c915e3bSDominik Adamski       ifClauseOperand = getIfClauseOperand(converter, stmtCtx, ifClause);
6871d328446SSourabh Singh Tomar     } else if (const auto &numThreadsClause =
6881d328446SSourabh Singh Tomar                    std::get_if<Fortran::parser::OmpClause::NumThreads>(
6891d328446SSourabh Singh Tomar                        &clause.u)) {
69034b08487SSourabh Singh Tomar       // OMPIRBuilder expects `NUM_THREAD` clause as a `Value`.
6911d328446SSourabh Singh Tomar       numThreadsClauseOperand = fir::getBase(converter.genExprValue(
692d0b70a07SValentin Clement           *Fortran::semantics::GetExpr(numThreadsClause->v), stmtCtx));
693fa4b1e1eSShraiysh Vaishay     } else if (const auto &procBindClause =
694fa4b1e1eSShraiysh Vaishay                    std::get_if<Fortran::parser::OmpClause::ProcBind>(
695fa4b1e1eSShraiysh Vaishay                        &clause.u)) {
6964202d69dSKiran Chandramohan       procBindKindAttr = genProcBindKindAttr(firOpBuilder, procBindClause);
697fa4b1e1eSShraiysh Vaishay     } else if (const auto &allocateClause =
698fa4b1e1eSShraiysh Vaishay                    std::get_if<Fortran::parser::OmpClause::Allocate>(
699fa4b1e1eSShraiysh Vaishay                        &clause.u)) {
700fa4b1e1eSShraiysh Vaishay       genAllocateClause(converter, allocateClause->v, allocatorOperands,
701fa4b1e1eSShraiysh Vaishay                         allocateOperands);
70207e16a2aSKiran Chandramohan     } else if (std::get_if<Fortran::parser::OmpClause::Private>(&clause.u) ||
70307e16a2aSKiran Chandramohan                std::get_if<Fortran::parser::OmpClause::Firstprivate>(
70427afb362SPeixin-Qiao                    &clause.u) ||
70527afb362SPeixin-Qiao                std::get_if<Fortran::parser::OmpClause::Copyin>(&clause.u)) {
70627afb362SPeixin-Qiao       // Privatisation and copyin clauses are handled elsewhere.
70707e16a2aSKiran Chandramohan       continue;
708051dea82SKiran Chandramohan     } else if (std::get_if<Fortran::parser::OmpClause::Shared>(&clause.u)) {
709051dea82SKiran Chandramohan       // Shared is the default behavior in the IR, so no handling is required.
710051dea82SKiran Chandramohan       continue;
711051dea82SKiran Chandramohan     } else if (const auto &defaultClause =
712051dea82SKiran Chandramohan                    std::get_if<Fortran::parser::OmpClause::Default>(
713051dea82SKiran Chandramohan                        &clause.u)) {
714051dea82SKiran Chandramohan       if ((defaultClause->v.v ==
715051dea82SKiran Chandramohan            Fortran::parser::OmpDefaultClause::Type::Shared) ||
716051dea82SKiran Chandramohan           (defaultClause->v.v ==
717051dea82SKiran Chandramohan            Fortran::parser::OmpDefaultClause::Type::None)) {
718051dea82SKiran Chandramohan         // Default clause with shared or none do not require any handling since
719051dea82SKiran Chandramohan         // Shared is the default behavior in the IR and None is only required
720051dea82SKiran Chandramohan         // for semantic checks.
721051dea82SKiran Chandramohan         continue;
722051dea82SKiran Chandramohan       }
7238964a17dSPeixinQiao     } else if (std::get_if<Fortran::parser::OmpClause::Threads>(&clause.u)) {
7248964a17dSPeixinQiao       // Nothing needs to be done for threads clause.
7258964a17dSPeixinQiao       continue;
72604cb01cfSShraiysh Vaishay     } else if (const auto &finalClause =
72704cb01cfSShraiysh Vaishay                    std::get_if<Fortran::parser::OmpClause::Final>(&clause.u)) {
72804cb01cfSShraiysh Vaishay       mlir::Value finalVal = fir::getBase(converter.genExprValue(
72904cb01cfSShraiysh Vaishay           *Fortran::semantics::GetExpr(finalClause->v), stmtCtx));
73004cb01cfSShraiysh Vaishay       finalClauseOperand = firOpBuilder.createConvert(
73104cb01cfSShraiysh Vaishay           currentLocation, firOpBuilder.getI1Type(), finalVal);
73204cb01cfSShraiysh Vaishay     } else if (std::get_if<Fortran::parser::OmpClause::Untied>(&clause.u)) {
73304cb01cfSShraiysh Vaishay       untiedAttr = firOpBuilder.getUnitAttr();
73404cb01cfSShraiysh Vaishay     } else if (std::get_if<Fortran::parser::OmpClause::Mergeable>(&clause.u)) {
73504cb01cfSShraiysh Vaishay       mergeableAttr = firOpBuilder.getUnitAttr();
73604cb01cfSShraiysh Vaishay     } else if (const auto &priorityClause =
73704cb01cfSShraiysh Vaishay                    std::get_if<Fortran::parser::OmpClause::Priority>(
73804cb01cfSShraiysh Vaishay                        &clause.u)) {
73904cb01cfSShraiysh Vaishay       priorityClauseOperand = fir::getBase(converter.genExprValue(
74004cb01cfSShraiysh Vaishay           *Fortran::semantics::GetExpr(priorityClause->v), stmtCtx));
741fa4b1e1eSShraiysh Vaishay     } else {
742fa4b1e1eSShraiysh Vaishay       TODO(currentLocation, "OpenMP Block construct clauses");
7431d328446SSourabh Singh Tomar     }
7441d328446SSourabh Singh Tomar   }
745fa4b1e1eSShraiysh Vaishay 
746fa4b1e1eSShraiysh Vaishay   for (const auto &clause :
747fa4b1e1eSShraiysh Vaishay        std::get<Fortran::parser::OmpClauseList>(endBlockDirective.t).v) {
748fa4b1e1eSShraiysh Vaishay     if (std::get_if<Fortran::parser::OmpClause::Nowait>(&clause.u))
749fa4b1e1eSShraiysh Vaishay       nowaitAttr = firOpBuilder.getUnitAttr();
750fa4b1e1eSShraiysh Vaishay   }
751fa4b1e1eSShraiysh Vaishay 
752fa4b1e1eSShraiysh Vaishay   if (blockDirective.v == llvm::omp::OMPD_parallel) {
753fa4b1e1eSShraiysh Vaishay     // Create and insert the operation.
754fa4b1e1eSShraiysh Vaishay     auto parallelOp = firOpBuilder.create<mlir::omp::ParallelOp>(
755fa4b1e1eSShraiysh Vaishay         currentLocation, argTy, ifClauseOperand, numThreadsClauseOperand,
756fa4b1e1eSShraiysh Vaishay         allocateOperands, allocatorOperands, /*reduction_vars=*/ValueRange(),
757fa4b1e1eSShraiysh Vaishay         /*reductions=*/nullptr, procBindKindAttr);
75807e16a2aSKiran Chandramohan     createBodyOfOp<omp::ParallelOp>(parallelOp, converter, currentLocation,
75929f167abSKiran Chandramohan                                     eval, &opClauseList);
7601d328446SSourabh Singh Tomar   } else if (blockDirective.v == llvm::omp::OMPD_master) {
7611d328446SSourabh Singh Tomar     auto masterOp =
7621d328446SSourabh Singh Tomar         firOpBuilder.create<mlir::omp::MasterOp>(currentLocation, argTy);
76329f167abSKiran Chandramohan     createBodyOfOp<omp::MasterOp>(masterOp, converter, currentLocation, eval);
764cd28353eSShraiysh Vaishay   } else if (blockDirective.v == llvm::omp::OMPD_single) {
765cd28353eSShraiysh Vaishay     auto singleOp = firOpBuilder.create<mlir::omp::SingleOp>(
766fa4b1e1eSShraiysh Vaishay         currentLocation, allocateOperands, allocatorOperands, nowaitAttr);
76729f167abSKiran Chandramohan     createBodyOfOp<omp::SingleOp>(singleOp, converter, currentLocation, eval);
7688964a17dSPeixinQiao   } else if (blockDirective.v == llvm::omp::OMPD_ordered) {
7698964a17dSPeixinQiao     auto orderedOp = firOpBuilder.create<mlir::omp::OrderedRegionOp>(
7708964a17dSPeixinQiao         currentLocation, /*simd=*/nullptr);
77129f167abSKiran Chandramohan     createBodyOfOp<omp::OrderedRegionOp>(orderedOp, converter, currentLocation,
77229f167abSKiran Chandramohan                                          eval);
77304cb01cfSShraiysh Vaishay   } else if (blockDirective.v == llvm::omp::OMPD_task) {
77404cb01cfSShraiysh Vaishay     auto taskOp = firOpBuilder.create<mlir::omp::TaskOp>(
77504cb01cfSShraiysh Vaishay         currentLocation, ifClauseOperand, finalClauseOperand, untiedAttr,
77604cb01cfSShraiysh Vaishay         mergeableAttr, /*in_reduction_vars=*/ValueRange(),
77704cb01cfSShraiysh Vaishay         /*in_reductions=*/nullptr, priorityClauseOperand, allocateOperands,
77804cb01cfSShraiysh Vaishay         allocatorOperands);
77929f167abSKiran Chandramohan     createBodyOfOp(taskOp, converter, currentLocation, eval, &opClauseList);
78007e16a2aSKiran Chandramohan   } else {
78107e16a2aSKiran Chandramohan     TODO(converter.getCurrentLocation(), "Unhandled block directive");
782bf812c14SSourabh Singh Tomar   }
783bf812c14SSourabh Singh Tomar }
784bf812c14SSourabh Singh Tomar 
7857bb1151bSKiran Chandramohan /// Creates an OpenMP reduction declaration and inserts it into the provided
7867bb1151bSKiran Chandramohan /// symbol table. The declaration has a constant initializer with the neutral
7877bb1151bSKiran Chandramohan /// value `initValue`, and the reduction combiner carried over from `reduce`.
7887bb1151bSKiran Chandramohan /// TODO: Generalize this for non-integer types, add atomic region.
createReductionDecl(fir::FirOpBuilder & builder,llvm::StringRef name,mlir::Type type,mlir::Location loc)7897bb1151bSKiran Chandramohan static omp::ReductionDeclareOp createReductionDecl(fir::FirOpBuilder &builder,
7907bb1151bSKiran Chandramohan                                                    llvm::StringRef name,
7917bb1151bSKiran Chandramohan                                                    mlir::Type type,
7927bb1151bSKiran Chandramohan                                                    mlir::Location loc) {
7937bb1151bSKiran Chandramohan   OpBuilder::InsertionGuard guard(builder);
7947bb1151bSKiran Chandramohan   mlir::ModuleOp module = builder.getModule();
7957bb1151bSKiran Chandramohan   mlir::OpBuilder modBuilder(module.getBodyRegion());
7967bb1151bSKiran Chandramohan   auto decl = module.lookupSymbol<mlir::omp::ReductionDeclareOp>(name);
7977bb1151bSKiran Chandramohan   if (!decl)
7987bb1151bSKiran Chandramohan     decl = modBuilder.create<omp::ReductionDeclareOp>(loc, name, type);
7997bb1151bSKiran Chandramohan   else
8007bb1151bSKiran Chandramohan     return decl;
8017bb1151bSKiran Chandramohan 
8027bb1151bSKiran Chandramohan   builder.createBlock(&decl.initializerRegion(), decl.initializerRegion().end(),
8037bb1151bSKiran Chandramohan                       {type}, {loc});
8047bb1151bSKiran Chandramohan   builder.setInsertionPointToEnd(&decl.initializerRegion().back());
8057bb1151bSKiran Chandramohan   Value init = builder.create<mlir::arith::ConstantOp>(
8067bb1151bSKiran Chandramohan       loc, type, builder.getIntegerAttr(type, 0));
8077bb1151bSKiran Chandramohan   builder.create<omp::YieldOp>(loc, init);
8087bb1151bSKiran Chandramohan 
8097bb1151bSKiran Chandramohan   builder.createBlock(&decl.reductionRegion(), decl.reductionRegion().end(),
8107bb1151bSKiran Chandramohan                       {type, type}, {loc, loc});
8117bb1151bSKiran Chandramohan   builder.setInsertionPointToEnd(&decl.reductionRegion().back());
8127bb1151bSKiran Chandramohan   mlir::Value op1 = decl.reductionRegion().front().getArgument(0);
8137bb1151bSKiran Chandramohan   mlir::Value op2 = decl.reductionRegion().front().getArgument(1);
8147bb1151bSKiran Chandramohan   Value addRes = builder.create<mlir::arith::AddIOp>(loc, op1, op2);
8157bb1151bSKiran Chandramohan   builder.create<omp::YieldOp>(loc, addRes);
8167bb1151bSKiran Chandramohan   return decl;
8177bb1151bSKiran Chandramohan }
8187bb1151bSKiran Chandramohan 
8198b951e64SKiran Chandramohan static mlir::omp::ScheduleModifier
translateModifier(const Fortran::parser::OmpScheduleModifierType & m)8208b951e64SKiran Chandramohan translateModifier(const Fortran::parser::OmpScheduleModifierType &m) {
8218b951e64SKiran Chandramohan   switch (m.v) {
8228b951e64SKiran Chandramohan   case Fortran::parser::OmpScheduleModifierType::ModType::Monotonic:
8238b951e64SKiran Chandramohan     return mlir::omp::ScheduleModifier::monotonic;
8248b951e64SKiran Chandramohan   case Fortran::parser::OmpScheduleModifierType::ModType::Nonmonotonic:
8258b951e64SKiran Chandramohan     return mlir::omp::ScheduleModifier::nonmonotonic;
8268b951e64SKiran Chandramohan   case Fortran::parser::OmpScheduleModifierType::ModType::Simd:
8278b951e64SKiran Chandramohan     return mlir::omp::ScheduleModifier::simd;
8288b951e64SKiran Chandramohan   }
8298b951e64SKiran Chandramohan   return mlir::omp::ScheduleModifier::none;
8308b951e64SKiran Chandramohan }
8318b951e64SKiran Chandramohan 
8328b951e64SKiran Chandramohan static mlir::omp::ScheduleModifier
getScheduleModifier(const Fortran::parser::OmpScheduleClause & x)8338b951e64SKiran Chandramohan getScheduleModifier(const Fortran::parser::OmpScheduleClause &x) {
8348b951e64SKiran Chandramohan   const auto &modifier =
8358b951e64SKiran Chandramohan       std::get<std::optional<Fortran::parser::OmpScheduleModifier>>(x.t);
8368b951e64SKiran Chandramohan   // The input may have the modifier any order, so we look for one that isn't
8378b951e64SKiran Chandramohan   // SIMD. If modifier is not set at all, fall down to the bottom and return
8388b951e64SKiran Chandramohan   // "none".
8398b951e64SKiran Chandramohan   if (modifier) {
8408b951e64SKiran Chandramohan     const auto &modType1 =
8418b951e64SKiran Chandramohan         std::get<Fortran::parser::OmpScheduleModifier::Modifier1>(modifier->t);
8428b951e64SKiran Chandramohan     if (modType1.v.v ==
8438b951e64SKiran Chandramohan         Fortran::parser::OmpScheduleModifierType::ModType::Simd) {
8448b951e64SKiran Chandramohan       const auto &modType2 = std::get<
8458b951e64SKiran Chandramohan           std::optional<Fortran::parser::OmpScheduleModifier::Modifier2>>(
8468b951e64SKiran Chandramohan           modifier->t);
8478b951e64SKiran Chandramohan       if (modType2 &&
8488b951e64SKiran Chandramohan           modType2->v.v !=
8498b951e64SKiran Chandramohan               Fortran::parser::OmpScheduleModifierType::ModType::Simd)
8508b951e64SKiran Chandramohan         return translateModifier(modType2->v);
8518b951e64SKiran Chandramohan 
8528b951e64SKiran Chandramohan       return mlir::omp::ScheduleModifier::none;
8538b951e64SKiran Chandramohan     }
8548b951e64SKiran Chandramohan 
8558b951e64SKiran Chandramohan     return translateModifier(modType1.v);
8568b951e64SKiran Chandramohan   }
8578b951e64SKiran Chandramohan   return mlir::omp::ScheduleModifier::none;
8588b951e64SKiran Chandramohan }
8598b951e64SKiran Chandramohan 
8608b951e64SKiran Chandramohan static mlir::omp::ScheduleModifier
getSIMDModifier(const Fortran::parser::OmpScheduleClause & x)8618b951e64SKiran Chandramohan getSIMDModifier(const Fortran::parser::OmpScheduleClause &x) {
8628b951e64SKiran Chandramohan   const auto &modifier =
8638b951e64SKiran Chandramohan       std::get<std::optional<Fortran::parser::OmpScheduleModifier>>(x.t);
8648b951e64SKiran Chandramohan   // Either of the two possible modifiers in the input can be the SIMD modifier,
8658b951e64SKiran Chandramohan   // so look in either one, and return simd if we find one. Not found = return
8668b951e64SKiran Chandramohan   // "none".
8678b951e64SKiran Chandramohan   if (modifier) {
8688b951e64SKiran Chandramohan     const auto &modType1 =
8698b951e64SKiran Chandramohan         std::get<Fortran::parser::OmpScheduleModifier::Modifier1>(modifier->t);
8708b951e64SKiran Chandramohan     if (modType1.v.v == Fortran::parser::OmpScheduleModifierType::ModType::Simd)
8718b951e64SKiran Chandramohan       return mlir::omp::ScheduleModifier::simd;
8728b951e64SKiran Chandramohan 
8738b951e64SKiran Chandramohan     const auto &modType2 = std::get<
8748b951e64SKiran Chandramohan         std::optional<Fortran::parser::OmpScheduleModifier::Modifier2>>(
8758b951e64SKiran Chandramohan         modifier->t);
8768b951e64SKiran Chandramohan     if (modType2 && modType2->v.v ==
8778b951e64SKiran Chandramohan                         Fortran::parser::OmpScheduleModifierType::ModType::Simd)
8788b951e64SKiran Chandramohan       return mlir::omp::ScheduleModifier::simd;
8798b951e64SKiran Chandramohan   }
8808b951e64SKiran Chandramohan   return mlir::omp::ScheduleModifier::none;
8818b951e64SKiran Chandramohan }
8828b951e64SKiran Chandramohan 
getReductionName(Fortran::parser::DefinedOperator::IntrinsicOperator intrinsicOp,mlir::Type ty)8837bb1151bSKiran Chandramohan static std::string getReductionName(
8847bb1151bSKiran Chandramohan     Fortran::parser::DefinedOperator::IntrinsicOperator intrinsicOp,
8857bb1151bSKiran Chandramohan     mlir::Type ty) {
8867bb1151bSKiran Chandramohan   std::string reductionName;
8877bb1151bSKiran Chandramohan   if (intrinsicOp == Fortran::parser::DefinedOperator::IntrinsicOperator::Add)
8887bb1151bSKiran Chandramohan     reductionName = "add_reduction";
8897bb1151bSKiran Chandramohan   else
8907bb1151bSKiran Chandramohan     reductionName = "other_reduction";
8917bb1151bSKiran Chandramohan 
8927bb1151bSKiran Chandramohan   return (llvm::Twine(reductionName) +
8937bb1151bSKiran Chandramohan           (ty.isIntOrIndex() ? llvm::Twine("_i_") : llvm::Twine("_f_")) +
8947bb1151bSKiran Chandramohan           llvm::Twine(ty.getIntOrFloatBitWidth()))
8957bb1151bSKiran Chandramohan       .str();
8967bb1151bSKiran Chandramohan }
8977bb1151bSKiran Chandramohan 
genOMP(Fortran::lower::AbstractConverter & converter,Fortran::lower::pft::Evaluation & eval,const Fortran::parser::OpenMPLoopConstruct & loopConstruct)898b85c39ddSKiran Chandramohan static void genOMP(Fortran::lower::AbstractConverter &converter,
899b85c39ddSKiran Chandramohan                    Fortran::lower::pft::Evaluation &eval,
900b85c39ddSKiran Chandramohan                    const Fortran::parser::OpenMPLoopConstruct &loopConstruct) {
901b85c39ddSKiran Chandramohan 
902b85c39ddSKiran Chandramohan   fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();
903b85c39ddSKiran Chandramohan   mlir::Location currentLocation = converter.getCurrentLocation();
904b85c39ddSKiran Chandramohan   llvm::SmallVector<mlir::Value> lowerBound, upperBound, step, linearVars,
905b85c39ddSKiran Chandramohan       linearStepVars, reductionVars;
9062c915e3bSDominik Adamski   mlir::Value scheduleChunkClauseOperand, ifClauseOperand;
9071795f8cdSPeixin-Qiao   mlir::Attribute scheduleClauseOperand, noWaitClauseOperand,
9081795f8cdSPeixin-Qiao       orderedClauseOperand, orderClauseOperand;
9097bb1151bSKiran Chandramohan   SmallVector<Attribute> reductionDeclSymbols;
9102c915e3bSDominik Adamski   Fortran::lower::StatementContext stmtCtx;
9113f4a63e5SArnamoy Bhattacharyya   const auto &loopOpClauseList = std::get<Fortran::parser::OmpClauseList>(
912b85c39ddSKiran Chandramohan       std::get<Fortran::parser::OmpBeginLoopDirective>(loopConstruct.t).t);
9134202d69dSKiran Chandramohan 
9144202d69dSKiran Chandramohan   const auto ompDirective =
915b85c39ddSKiran Chandramohan       std::get<Fortran::parser::OmpLoopDirective>(
916b85c39ddSKiran Chandramohan           std::get<Fortran::parser::OmpBeginLoopDirective>(loopConstruct.t).t)
9174202d69dSKiran Chandramohan           .v;
9184202d69dSKiran Chandramohan   if (llvm::omp::OMPD_parallel_do == ompDirective) {
9194202d69dSKiran Chandramohan     createCombinedParallelOp<Fortran::parser::OmpBeginLoopDirective>(
9204202d69dSKiran Chandramohan         converter, eval,
9214202d69dSKiran Chandramohan         std::get<Fortran::parser::OmpBeginLoopDirective>(loopConstruct.t));
9223f4a63e5SArnamoy Bhattacharyya   } else if (llvm::omp::OMPD_do != ompDirective &&
9233f4a63e5SArnamoy Bhattacharyya              llvm::omp::OMPD_simd != ompDirective) {
9244202d69dSKiran Chandramohan     TODO(converter.getCurrentLocation(), "Construct enclosing do loop");
925b85c39ddSKiran Chandramohan   }
926b85c39ddSKiran Chandramohan 
9273b390a16SMats Petersson   // Collect the loops to collapse.
9283b390a16SMats Petersson   auto *doConstructEval = &eval.getFirstNestedEvaluation();
9293b390a16SMats Petersson 
930870f4421SPeixin-Qiao   std::int64_t collapseValue =
9313f4a63e5SArnamoy Bhattacharyya       Fortran::lower::getCollapseValue(loopOpClauseList);
932870f4421SPeixin-Qiao   std::size_t loopVarTypeSize = 0;
9333b390a16SMats Petersson   SmallVector<const Fortran::semantics::Symbol *> iv;
9343b390a16SMats Petersson   do {
9353b390a16SMats Petersson     auto *doLoop = &doConstructEval->getFirstNestedEvaluation();
936b85c39ddSKiran Chandramohan     auto *doStmt = doLoop->getIf<Fortran::parser::NonLabelDoStmt>();
937b85c39ddSKiran Chandramohan     assert(doStmt && "Expected do loop to be in the nested evaluation");
938b85c39ddSKiran Chandramohan     const auto &loopControl =
939b85c39ddSKiran Chandramohan         std::get<std::optional<Fortran::parser::LoopControl>>(doStmt->t);
940b85c39ddSKiran Chandramohan     const Fortran::parser::LoopControl::Bounds *bounds =
941b85c39ddSKiran Chandramohan         std::get_if<Fortran::parser::LoopControl::Bounds>(&loopControl->u);
942b85c39ddSKiran Chandramohan     assert(bounds && "Expected bounds for worksharing do loop");
943b85c39ddSKiran Chandramohan     Fortran::lower::StatementContext stmtCtx;
944b85c39ddSKiran Chandramohan     lowerBound.push_back(fir::getBase(converter.genExprValue(
945b85c39ddSKiran Chandramohan         *Fortran::semantics::GetExpr(bounds->lower), stmtCtx)));
946b85c39ddSKiran Chandramohan     upperBound.push_back(fir::getBase(converter.genExprValue(
947b85c39ddSKiran Chandramohan         *Fortran::semantics::GetExpr(bounds->upper), stmtCtx)));
948b85c39ddSKiran Chandramohan     if (bounds->step) {
949b85c39ddSKiran Chandramohan       step.push_back(fir::getBase(converter.genExprValue(
950b85c39ddSKiran Chandramohan           *Fortran::semantics::GetExpr(bounds->step), stmtCtx)));
951b85c39ddSKiran Chandramohan     } else { // If `step` is not present, assume it as `1`.
952b85c39ddSKiran Chandramohan       step.push_back(firOpBuilder.createIntegerConstant(
953b85c39ddSKiran Chandramohan           currentLocation, firOpBuilder.getIntegerType(32), 1));
954b85c39ddSKiran Chandramohan     }
9553b390a16SMats Petersson     iv.push_back(bounds->name.thing.symbol);
956870f4421SPeixin-Qiao     loopVarTypeSize = std::max(loopVarTypeSize,
957870f4421SPeixin-Qiao                                bounds->name.thing.symbol->GetUltimate().size());
9583b390a16SMats Petersson 
9593b390a16SMats Petersson     collapseValue--;
9603b390a16SMats Petersson     doConstructEval =
9613b390a16SMats Petersson         &*std::next(doConstructEval->getNestedEvaluations().begin());
9623b390a16SMats Petersson   } while (collapseValue > 0);
963b85c39ddSKiran Chandramohan 
9643f4a63e5SArnamoy Bhattacharyya   for (const auto &clause : loopOpClauseList.v) {
965820146abSMats Petersson     if (const auto &scheduleClause =
966820146abSMats Petersson             std::get_if<Fortran::parser::OmpClause::Schedule>(&clause.u)) {
967820146abSMats Petersson       if (const auto &chunkExpr =
968820146abSMats Petersson               std::get<std::optional<Fortran::parser::ScalarIntExpr>>(
969820146abSMats Petersson                   scheduleClause->v.t)) {
970820146abSMats Petersson         if (const auto *expr = Fortran::semantics::GetExpr(*chunkExpr)) {
971820146abSMats Petersson           scheduleChunkClauseOperand =
972820146abSMats Petersson               fir::getBase(converter.genExprValue(*expr, stmtCtx));
973820146abSMats Petersson         }
974820146abSMats Petersson       }
9752c915e3bSDominik Adamski     } else if (const auto &ifClause =
9762c915e3bSDominik Adamski                    std::get_if<Fortran::parser::OmpClause::If>(&clause.u)) {
9772c915e3bSDominik Adamski       ifClauseOperand = getIfClauseOperand(converter, stmtCtx, ifClause);
9787bb1151bSKiran Chandramohan     } else if (const auto &reductionClause =
9797bb1151bSKiran Chandramohan                    std::get_if<Fortran::parser::OmpClause::Reduction>(
9807bb1151bSKiran Chandramohan                        &clause.u)) {
9817bb1151bSKiran Chandramohan       omp::ReductionDeclareOp decl;
9827bb1151bSKiran Chandramohan       const auto &redOperator{std::get<Fortran::parser::OmpReductionOperator>(
9837bb1151bSKiran Chandramohan           reductionClause->v.t)};
9847bb1151bSKiran Chandramohan       const auto &objectList{
9857bb1151bSKiran Chandramohan           std::get<Fortran::parser::OmpObjectList>(reductionClause->v.t)};
9867bb1151bSKiran Chandramohan       if (const auto &redDefinedOp =
9877bb1151bSKiran Chandramohan               std::get_if<Fortran::parser::DefinedOperator>(&redOperator.u)) {
9887bb1151bSKiran Chandramohan         const auto &intrinsicOp{
9897bb1151bSKiran Chandramohan             std::get<Fortran::parser::DefinedOperator::IntrinsicOperator>(
9907bb1151bSKiran Chandramohan                 redDefinedOp->u)};
9917bb1151bSKiran Chandramohan         if (intrinsicOp !=
9927bb1151bSKiran Chandramohan             Fortran::parser::DefinedOperator::IntrinsicOperator::Add)
9937bb1151bSKiran Chandramohan           TODO(currentLocation,
9947bb1151bSKiran Chandramohan                "Reduction of some intrinsic operators is not supported");
9957bb1151bSKiran Chandramohan         for (const auto &ompObject : objectList.v) {
9967bb1151bSKiran Chandramohan           if (const auto *name{
9977bb1151bSKiran Chandramohan                   Fortran::parser::Unwrap<Fortran::parser::Name>(ompObject)}) {
9987bb1151bSKiran Chandramohan             if (const auto *symbol{name->symbol}) {
9997bb1151bSKiran Chandramohan               mlir::Value symVal = converter.getSymbolAddress(*symbol);
10007bb1151bSKiran Chandramohan               mlir::Type redType =
10017bb1151bSKiran Chandramohan                   symVal.getType().cast<fir::ReferenceType>().getEleTy();
10027bb1151bSKiran Chandramohan               reductionVars.push_back(symVal);
10037bb1151bSKiran Chandramohan               if (redType.isIntOrIndex()) {
10047bb1151bSKiran Chandramohan                 decl = createReductionDecl(
10057bb1151bSKiran Chandramohan                     firOpBuilder, getReductionName(intrinsicOp, redType),
10067bb1151bSKiran Chandramohan                     redType, currentLocation);
10077bb1151bSKiran Chandramohan               } else {
10087bb1151bSKiran Chandramohan                 TODO(currentLocation,
10097bb1151bSKiran Chandramohan                      "Reduction of some types is not supported");
10107bb1151bSKiran Chandramohan               }
10117bb1151bSKiran Chandramohan               reductionDeclSymbols.push_back(SymbolRefAttr::get(
10127bb1151bSKiran Chandramohan                   firOpBuilder.getContext(), decl.sym_name()));
10137bb1151bSKiran Chandramohan             }
10147bb1151bSKiran Chandramohan           }
10157bb1151bSKiran Chandramohan         }
10167bb1151bSKiran Chandramohan       } else {
10177bb1151bSKiran Chandramohan         TODO(currentLocation,
10187bb1151bSKiran Chandramohan              "Reduction of intrinsic procedures is not supported");
10197bb1151bSKiran Chandramohan       }
1020820146abSMats Petersson     }
1021820146abSMats Petersson   }
1022820146abSMats Petersson 
1023870f4421SPeixin-Qiao   // The types of lower bound, upper bound, and step are converted into the
1024870f4421SPeixin-Qiao   // type of the loop variable if necessary.
1025870f4421SPeixin-Qiao   mlir::Type loopVarType = getLoopVarType(converter, loopVarTypeSize);
1026870f4421SPeixin-Qiao   for (unsigned it = 0; it < (unsigned)lowerBound.size(); it++) {
1027870f4421SPeixin-Qiao     lowerBound[it] = firOpBuilder.createConvert(currentLocation, loopVarType,
1028870f4421SPeixin-Qiao                                                 lowerBound[it]);
1029870f4421SPeixin-Qiao     upperBound[it] = firOpBuilder.createConvert(currentLocation, loopVarType,
1030870f4421SPeixin-Qiao                                                 upperBound[it]);
1031870f4421SPeixin-Qiao     step[it] =
1032870f4421SPeixin-Qiao         firOpBuilder.createConvert(currentLocation, loopVarType, step[it]);
1033870f4421SPeixin-Qiao   }
1034870f4421SPeixin-Qiao 
10353f4a63e5SArnamoy Bhattacharyya   // 2.9.3.1 SIMD construct
10363f4a63e5SArnamoy Bhattacharyya   // TODO: Support all the clauses
10373f4a63e5SArnamoy Bhattacharyya   if (llvm::omp::OMPD_simd == ompDirective) {
10383f4a63e5SArnamoy Bhattacharyya     TypeRange resultType;
10393f4a63e5SArnamoy Bhattacharyya     auto SimdLoopOp = firOpBuilder.create<mlir::omp::SimdLoopOp>(
10402c915e3bSDominik Adamski         currentLocation, resultType, lowerBound, upperBound, step,
10412c915e3bSDominik Adamski         ifClauseOperand, /*inclusive=*/firOpBuilder.getUnitAttr());
10423f4a63e5SArnamoy Bhattacharyya     createBodyOfOp<omp::SimdLoopOp>(SimdLoopOp, converter, currentLocation,
10433f4a63e5SArnamoy Bhattacharyya                                     eval, &loopOpClauseList, iv);
10443f4a63e5SArnamoy Bhattacharyya     return;
10453f4a63e5SArnamoy Bhattacharyya   }
10463f4a63e5SArnamoy Bhattacharyya 
1047b85c39ddSKiran Chandramohan   // FIXME: Add support for following clauses:
1048b85c39ddSKiran Chandramohan   // 1. linear
1049b85c39ddSKiran Chandramohan   // 2. order
1050b85c39ddSKiran Chandramohan   auto wsLoopOp = firOpBuilder.create<mlir::omp::WsLoopOp>(
1051b85c39ddSKiran Chandramohan       currentLocation, lowerBound, upperBound, step, linearVars, linearStepVars,
10527bb1151bSKiran Chandramohan       reductionVars,
10537bb1151bSKiran Chandramohan       reductionDeclSymbols.empty()
10547bb1151bSKiran Chandramohan           ? nullptr
10557bb1151bSKiran Chandramohan           : mlir::ArrayAttr::get(firOpBuilder.getContext(),
10567bb1151bSKiran Chandramohan                                  reductionDeclSymbols),
1057b85c39ddSKiran Chandramohan       scheduleClauseOperand.dyn_cast_or_null<omp::ClauseScheduleKindAttr>(),
1058b85c39ddSKiran Chandramohan       scheduleChunkClauseOperand, /*schedule_modifiers=*/nullptr,
1059b85c39ddSKiran Chandramohan       /*simd_modifier=*/nullptr,
1060b85c39ddSKiran Chandramohan       noWaitClauseOperand.dyn_cast_or_null<UnitAttr>(),
1061b85c39ddSKiran Chandramohan       orderedClauseOperand.dyn_cast_or_null<IntegerAttr>(),
1062b85c39ddSKiran Chandramohan       orderClauseOperand.dyn_cast_or_null<omp::ClauseOrderKindAttr>(),
1063b85c39ddSKiran Chandramohan       /*inclusive=*/firOpBuilder.getUnitAttr());
1064b85c39ddSKiran Chandramohan 
1065b85c39ddSKiran Chandramohan   // Handle attribute based clauses.
10663f4a63e5SArnamoy Bhattacharyya   for (const Fortran::parser::OmpClause &clause : loopOpClauseList.v) {
1067f305ac3dSPeixin-Qiao     if (const auto &orderedClause =
1068f305ac3dSPeixin-Qiao             std::get_if<Fortran::parser::OmpClause::Ordered>(&clause.u)) {
1069f305ac3dSPeixin-Qiao       if (orderedClause->v.has_value()) {
1070f305ac3dSPeixin-Qiao         const auto *expr = Fortran::semantics::GetExpr(orderedClause->v);
1071f305ac3dSPeixin-Qiao         const std::optional<std::int64_t> orderedClauseValue =
1072f305ac3dSPeixin-Qiao             Fortran::evaluate::ToInt64(*expr);
1073f305ac3dSPeixin-Qiao         wsLoopOp.ordered_valAttr(
1074f305ac3dSPeixin-Qiao             firOpBuilder.getI64IntegerAttr(*orderedClauseValue));
1075f305ac3dSPeixin-Qiao       } else {
1076f305ac3dSPeixin-Qiao         wsLoopOp.ordered_valAttr(firOpBuilder.getI64IntegerAttr(0));
1077f305ac3dSPeixin-Qiao       }
1078f305ac3dSPeixin-Qiao     } else if (const auto &scheduleClause =
1079f305ac3dSPeixin-Qiao                    std::get_if<Fortran::parser::OmpClause::Schedule>(
1080f305ac3dSPeixin-Qiao                        &clause.u)) {
1081b85c39ddSKiran Chandramohan       mlir::MLIRContext *context = firOpBuilder.getContext();
1082b85c39ddSKiran Chandramohan       const auto &scheduleType = scheduleClause->v;
1083b85c39ddSKiran Chandramohan       const auto &scheduleKind =
1084b85c39ddSKiran Chandramohan           std::get<Fortran::parser::OmpScheduleClause::ScheduleType>(
1085b85c39ddSKiran Chandramohan               scheduleType.t);
1086b85c39ddSKiran Chandramohan       switch (scheduleKind) {
1087b85c39ddSKiran Chandramohan       case Fortran::parser::OmpScheduleClause::ScheduleType::Static:
1088b85c39ddSKiran Chandramohan         wsLoopOp.schedule_valAttr(omp::ClauseScheduleKindAttr::get(
1089b85c39ddSKiran Chandramohan             context, omp::ClauseScheduleKind::Static));
1090b85c39ddSKiran Chandramohan         break;
1091b85c39ddSKiran Chandramohan       case Fortran::parser::OmpScheduleClause::ScheduleType::Dynamic:
1092b85c39ddSKiran Chandramohan         wsLoopOp.schedule_valAttr(omp::ClauseScheduleKindAttr::get(
1093b85c39ddSKiran Chandramohan             context, omp::ClauseScheduleKind::Dynamic));
1094b85c39ddSKiran Chandramohan         break;
1095b85c39ddSKiran Chandramohan       case Fortran::parser::OmpScheduleClause::ScheduleType::Guided:
1096b85c39ddSKiran Chandramohan         wsLoopOp.schedule_valAttr(omp::ClauseScheduleKindAttr::get(
1097b85c39ddSKiran Chandramohan             context, omp::ClauseScheduleKind::Guided));
1098b85c39ddSKiran Chandramohan         break;
1099b85c39ddSKiran Chandramohan       case Fortran::parser::OmpScheduleClause::ScheduleType::Auto:
1100b85c39ddSKiran Chandramohan         wsLoopOp.schedule_valAttr(omp::ClauseScheduleKindAttr::get(
1101b85c39ddSKiran Chandramohan             context, omp::ClauseScheduleKind::Auto));
1102b85c39ddSKiran Chandramohan         break;
1103b85c39ddSKiran Chandramohan       case Fortran::parser::OmpScheduleClause::ScheduleType::Runtime:
1104b85c39ddSKiran Chandramohan         wsLoopOp.schedule_valAttr(omp::ClauseScheduleKindAttr::get(
1105b85c39ddSKiran Chandramohan             context, omp::ClauseScheduleKind::Runtime));
1106b85c39ddSKiran Chandramohan         break;
1107b85c39ddSKiran Chandramohan       }
11088b951e64SKiran Chandramohan       mlir::omp::ScheduleModifier scheduleModifier =
11098b951e64SKiran Chandramohan           getScheduleModifier(scheduleClause->v);
11108b951e64SKiran Chandramohan       if (scheduleModifier != mlir::omp::ScheduleModifier::none)
11118b951e64SKiran Chandramohan         wsLoopOp.schedule_modifierAttr(
11128b951e64SKiran Chandramohan             omp::ScheduleModifierAttr::get(context, scheduleModifier));
11138b951e64SKiran Chandramohan       if (getSIMDModifier(scheduleClause->v) !=
11148b951e64SKiran Chandramohan           mlir::omp::ScheduleModifier::none)
11158b951e64SKiran Chandramohan         wsLoopOp.simd_modifierAttr(firOpBuilder.getUnitAttr());
1116b85c39ddSKiran Chandramohan     }
1117b85c39ddSKiran Chandramohan   }
1118b85c39ddSKiran Chandramohan   // In FORTRAN `nowait` clause occur at the end of `omp do` directive.
1119b85c39ddSKiran Chandramohan   // i.e
1120b85c39ddSKiran Chandramohan   // !$omp do
1121b85c39ddSKiran Chandramohan   // <...>
1122b85c39ddSKiran Chandramohan   // !$omp end do nowait
1123b85c39ddSKiran Chandramohan   if (const auto &endClauseList =
1124b85c39ddSKiran Chandramohan           std::get<std::optional<Fortran::parser::OmpEndLoopDirective>>(
1125b85c39ddSKiran Chandramohan               loopConstruct.t)) {
1126b85c39ddSKiran Chandramohan     const auto &clauseList =
1127b85c39ddSKiran Chandramohan         std::get<Fortran::parser::OmpClauseList>((*endClauseList).t);
1128b85c39ddSKiran Chandramohan     for (const Fortran::parser::OmpClause &clause : clauseList.v)
1129b85c39ddSKiran Chandramohan       if (std::get_if<Fortran::parser::OmpClause::Nowait>(&clause.u))
1130b85c39ddSKiran Chandramohan         wsLoopOp.nowaitAttr(firOpBuilder.getUnitAttr());
1131b85c39ddSKiran Chandramohan   }
1132b85c39ddSKiran Chandramohan 
113329f167abSKiran Chandramohan   createBodyOfOp<omp::WsLoopOp>(wsLoopOp, converter, currentLocation, eval,
11343f4a63e5SArnamoy Bhattacharyya                                 &loopOpClauseList, iv);
1135b85c39ddSKiran Chandramohan }
1136b85c39ddSKiran Chandramohan 
1137ebec5e5cSShraiysh Vaishay static void
genOMP(Fortran::lower::AbstractConverter & converter,Fortran::lower::pft::Evaluation & eval,const Fortran::parser::OpenMPCriticalConstruct & criticalConstruct)1138ebec5e5cSShraiysh Vaishay genOMP(Fortran::lower::AbstractConverter &converter,
1139ebec5e5cSShraiysh Vaishay        Fortran::lower::pft::Evaluation &eval,
1140ebec5e5cSShraiysh Vaishay        const Fortran::parser::OpenMPCriticalConstruct &criticalConstruct) {
1141ebec5e5cSShraiysh Vaishay   fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();
1142ebec5e5cSShraiysh Vaishay   mlir::Location currentLocation = converter.getCurrentLocation();
1143ebec5e5cSShraiysh Vaishay   std::string name;
1144ebec5e5cSShraiysh Vaishay   const Fortran::parser::OmpCriticalDirective &cd =
1145ebec5e5cSShraiysh Vaishay       std::get<Fortran::parser::OmpCriticalDirective>(criticalConstruct.t);
1146ebec5e5cSShraiysh Vaishay   if (std::get<std::optional<Fortran::parser::Name>>(cd.t).has_value()) {
1147ebec5e5cSShraiysh Vaishay     name =
1148ebec5e5cSShraiysh Vaishay         std::get<std::optional<Fortran::parser::Name>>(cd.t).value().ToString();
1149ebec5e5cSShraiysh Vaishay   }
1150ebec5e5cSShraiysh Vaishay 
1151ebec5e5cSShraiysh Vaishay   uint64_t hint = 0;
1152ebec5e5cSShraiysh Vaishay   const auto &clauseList = std::get<Fortran::parser::OmpClauseList>(cd.t);
1153ebec5e5cSShraiysh Vaishay   for (const Fortran::parser::OmpClause &clause : clauseList.v)
1154ebec5e5cSShraiysh Vaishay     if (auto hintClause =
1155ebec5e5cSShraiysh Vaishay             std::get_if<Fortran::parser::OmpClause::Hint>(&clause.u)) {
1156ebec5e5cSShraiysh Vaishay       const auto *expr = Fortran::semantics::GetExpr(hintClause->v);
1157ebec5e5cSShraiysh Vaishay       hint = *Fortran::evaluate::ToInt64(*expr);
1158ebec5e5cSShraiysh Vaishay       break;
1159ebec5e5cSShraiysh Vaishay     }
1160ebec5e5cSShraiysh Vaishay 
1161ebec5e5cSShraiysh Vaishay   mlir::omp::CriticalOp criticalOp = [&]() {
1162ebec5e5cSShraiysh Vaishay     if (name.empty()) {
1163ebec5e5cSShraiysh Vaishay       return firOpBuilder.create<mlir::omp::CriticalOp>(currentLocation,
1164ebec5e5cSShraiysh Vaishay                                                         FlatSymbolRefAttr());
1165ebec5e5cSShraiysh Vaishay     } else {
1166ebec5e5cSShraiysh Vaishay       mlir::ModuleOp module = firOpBuilder.getModule();
1167ebec5e5cSShraiysh Vaishay       mlir::OpBuilder modBuilder(module.getBodyRegion());
1168ebec5e5cSShraiysh Vaishay       auto global = module.lookupSymbol<mlir::omp::CriticalDeclareOp>(name);
1169ebec5e5cSShraiysh Vaishay       if (!global)
1170ebec5e5cSShraiysh Vaishay         global = modBuilder.create<mlir::omp::CriticalDeclareOp>(
1171ebec5e5cSShraiysh Vaishay             currentLocation, name, hint);
1172ebec5e5cSShraiysh Vaishay       return firOpBuilder.create<mlir::omp::CriticalOp>(
1173ebec5e5cSShraiysh Vaishay           currentLocation, mlir::FlatSymbolRefAttr::get(
1174ebec5e5cSShraiysh Vaishay                                firOpBuilder.getContext(), global.sym_name()));
1175ebec5e5cSShraiysh Vaishay     }
1176ebec5e5cSShraiysh Vaishay   }();
117729f167abSKiran Chandramohan   createBodyOfOp<omp::CriticalOp>(criticalOp, converter, currentLocation, eval);
1178ebec5e5cSShraiysh Vaishay }
1179ebec5e5cSShraiysh Vaishay 
118088d5289fSNimish Mishra static void
genOMP(Fortran::lower::AbstractConverter & converter,Fortran::lower::pft::Evaluation & eval,const Fortran::parser::OpenMPSectionConstruct & sectionConstruct)118188d5289fSNimish Mishra genOMP(Fortran::lower::AbstractConverter &converter,
118288d5289fSNimish Mishra        Fortran::lower::pft::Evaluation &eval,
118388d5289fSNimish Mishra        const Fortran::parser::OpenMPSectionConstruct &sectionConstruct) {
118488d5289fSNimish Mishra 
118588d5289fSNimish Mishra   auto &firOpBuilder = converter.getFirOpBuilder();
118688d5289fSNimish Mishra   auto currentLocation = converter.getCurrentLocation();
118788d5289fSNimish Mishra   mlir::omp::SectionOp sectionOp =
118888d5289fSNimish Mishra       firOpBuilder.create<mlir::omp::SectionOp>(currentLocation);
118929f167abSKiran Chandramohan   createBodyOfOp<omp::SectionOp>(sectionOp, converter, currentLocation, eval);
119088d5289fSNimish Mishra }
119188d5289fSNimish Mishra 
119288d5289fSNimish Mishra // TODO: Add support for reduction
119388d5289fSNimish Mishra static void
genOMP(Fortran::lower::AbstractConverter & converter,Fortran::lower::pft::Evaluation & eval,const Fortran::parser::OpenMPSectionsConstruct & sectionsConstruct)119488d5289fSNimish Mishra genOMP(Fortran::lower::AbstractConverter &converter,
119588d5289fSNimish Mishra        Fortran::lower::pft::Evaluation &eval,
119688d5289fSNimish Mishra        const Fortran::parser::OpenMPSectionsConstruct &sectionsConstruct) {
119788d5289fSNimish Mishra   auto &firOpBuilder = converter.getFirOpBuilder();
119888d5289fSNimish Mishra   auto currentLocation = converter.getCurrentLocation();
119988d5289fSNimish Mishra   SmallVector<Value> reductionVars, allocateOperands, allocatorOperands;
120088d5289fSNimish Mishra   mlir::UnitAttr noWaitClauseOperand;
120188d5289fSNimish Mishra   const auto &sectionsClauseList = std::get<Fortran::parser::OmpClauseList>(
120288d5289fSNimish Mishra       std::get<Fortran::parser::OmpBeginSectionsDirective>(sectionsConstruct.t)
120388d5289fSNimish Mishra           .t);
120488d5289fSNimish Mishra   for (const Fortran::parser::OmpClause &clause : sectionsClauseList.v) {
12051fe4b968SShraiysh Vaishay 
12061fe4b968SShraiysh Vaishay     // Reduction Clause
120788d5289fSNimish Mishra     if (std::get_if<Fortran::parser::OmpClause::Reduction>(&clause.u)) {
120888d5289fSNimish Mishra       TODO(currentLocation, "OMPC_Reduction");
12091fe4b968SShraiysh Vaishay 
12101fe4b968SShraiysh Vaishay       // Allocate clause
121188d5289fSNimish Mishra     } else if (const auto &allocateClause =
121288d5289fSNimish Mishra                    std::get_if<Fortran::parser::OmpClause::Allocate>(
121388d5289fSNimish Mishra                        &clause.u)) {
121488d5289fSNimish Mishra       genAllocateClause(converter, allocateClause->v, allocatorOperands,
121588d5289fSNimish Mishra                         allocateOperands);
121688d5289fSNimish Mishra     }
121788d5289fSNimish Mishra   }
121888d5289fSNimish Mishra   const auto &endSectionsClauseList =
121988d5289fSNimish Mishra       std::get<Fortran::parser::OmpEndSectionsDirective>(sectionsConstruct.t);
122088d5289fSNimish Mishra   const auto &clauseList =
122188d5289fSNimish Mishra       std::get<Fortran::parser::OmpClauseList>(endSectionsClauseList.t);
122288d5289fSNimish Mishra   for (const auto &clause : clauseList.v) {
12231fe4b968SShraiysh Vaishay     // Nowait clause
122488d5289fSNimish Mishra     if (std::get_if<Fortran::parser::OmpClause::Nowait>(&clause.u)) {
122588d5289fSNimish Mishra       noWaitClauseOperand = firOpBuilder.getUnitAttr();
122688d5289fSNimish Mishra     }
122788d5289fSNimish Mishra   }
122888d5289fSNimish Mishra 
12291fe4b968SShraiysh Vaishay   llvm::omp::Directive dir =
12301fe4b968SShraiysh Vaishay       std::get<Fortran::parser::OmpSectionsDirective>(
12311fe4b968SShraiysh Vaishay           std::get<Fortran::parser::OmpBeginSectionsDirective>(
12321fe4b968SShraiysh Vaishay               sectionsConstruct.t)
12331fe4b968SShraiysh Vaishay               .t)
12341fe4b968SShraiysh Vaishay           .v;
12351fe4b968SShraiysh Vaishay 
12361fe4b968SShraiysh Vaishay   // Parallel Sections Construct
12371fe4b968SShraiysh Vaishay   if (dir == llvm::omp::Directive::OMPD_parallel_sections) {
12384202d69dSKiran Chandramohan     createCombinedParallelOp<Fortran::parser::OmpBeginSectionsDirective>(
12394202d69dSKiran Chandramohan         converter, eval,
12404202d69dSKiran Chandramohan         std::get<Fortran::parser::OmpBeginSectionsDirective>(
12414202d69dSKiran Chandramohan             sectionsConstruct.t));
12421fe4b968SShraiysh Vaishay     auto sectionsOp = firOpBuilder.create<mlir::omp::SectionsOp>(
12431fe4b968SShraiysh Vaishay         currentLocation, /*reduction_vars*/ ValueRange(),
12444202d69dSKiran Chandramohan         /*reductions=*/nullptr, allocateOperands, allocatorOperands,
12454202d69dSKiran Chandramohan         /*nowait=*/nullptr);
124629f167abSKiran Chandramohan     createBodyOfOp(sectionsOp, converter, currentLocation, eval);
12471fe4b968SShraiysh Vaishay 
12481fe4b968SShraiysh Vaishay     // Sections Construct
12491fe4b968SShraiysh Vaishay   } else if (dir == llvm::omp::Directive::OMPD_sections) {
12501fe4b968SShraiysh Vaishay     auto sectionsOp = firOpBuilder.create<mlir::omp::SectionsOp>(
125188d5289fSNimish Mishra         currentLocation, reductionVars, /*reductions = */ nullptr,
125288d5289fSNimish Mishra         allocateOperands, allocatorOperands, noWaitClauseOperand);
125329f167abSKiran Chandramohan     createBodyOfOp<omp::SectionsOp>(sectionsOp, converter, currentLocation,
125429f167abSKiran Chandramohan                                     eval);
125588d5289fSNimish Mishra   }
12561fe4b968SShraiysh Vaishay }
125788d5289fSNimish Mishra 
genOmpAtomicHintAndMemoryOrderClauses(Fortran::lower::AbstractConverter & converter,const Fortran::parser::OmpAtomicClauseList & clauseList,mlir::IntegerAttr & hint,mlir::omp::ClauseMemoryOrderKindAttr & memory_order)125800c511b3SNimish Mishra static void genOmpAtomicHintAndMemoryOrderClauses(
125900c511b3SNimish Mishra     Fortran::lower::AbstractConverter &converter,
126000c511b3SNimish Mishra     const Fortran::parser::OmpAtomicClauseList &clauseList,
126100c511b3SNimish Mishra     mlir::IntegerAttr &hint,
126200c511b3SNimish Mishra     mlir::omp::ClauseMemoryOrderKindAttr &memory_order) {
126300c511b3SNimish Mishra   auto &firOpBuilder = converter.getFirOpBuilder();
126400c511b3SNimish Mishra   for (const auto &clause : clauseList.v) {
126500c511b3SNimish Mishra     if (auto ompClause = std::get_if<Fortran::parser::OmpClause>(&clause.u)) {
126600c511b3SNimish Mishra       if (auto hintClause =
126700c511b3SNimish Mishra               std::get_if<Fortran::parser::OmpClause::Hint>(&ompClause->u)) {
126800c511b3SNimish Mishra         const auto *expr = Fortran::semantics::GetExpr(hintClause->v);
126900c511b3SNimish Mishra         uint64_t hintExprValue = *Fortran::evaluate::ToInt64(*expr);
127000c511b3SNimish Mishra         hint = firOpBuilder.getI64IntegerAttr(hintExprValue);
127100c511b3SNimish Mishra       }
127200c511b3SNimish Mishra     } else if (auto ompMemoryOrderClause =
127300c511b3SNimish Mishra                    std::get_if<Fortran::parser::OmpMemoryOrderClause>(
127400c511b3SNimish Mishra                        &clause.u)) {
127500c511b3SNimish Mishra       if (std::get_if<Fortran::parser::OmpClause::Acquire>(
127600c511b3SNimish Mishra               &ompMemoryOrderClause->v.u)) {
127700c511b3SNimish Mishra         memory_order = mlir::omp::ClauseMemoryOrderKindAttr::get(
127800c511b3SNimish Mishra             firOpBuilder.getContext(), omp::ClauseMemoryOrderKind::Acquire);
127900c511b3SNimish Mishra       } else if (std::get_if<Fortran::parser::OmpClause::Relaxed>(
128000c511b3SNimish Mishra                      &ompMemoryOrderClause->v.u)) {
128100c511b3SNimish Mishra         memory_order = mlir::omp::ClauseMemoryOrderKindAttr::get(
128200c511b3SNimish Mishra             firOpBuilder.getContext(), omp::ClauseMemoryOrderKind::Relaxed);
128300c511b3SNimish Mishra       } else if (std::get_if<Fortran::parser::OmpClause::SeqCst>(
128400c511b3SNimish Mishra                      &ompMemoryOrderClause->v.u)) {
128500c511b3SNimish Mishra         memory_order = mlir::omp::ClauseMemoryOrderKindAttr::get(
128600c511b3SNimish Mishra             firOpBuilder.getContext(), omp::ClauseMemoryOrderKind::Seq_cst);
128700c511b3SNimish Mishra       } else if (std::get_if<Fortran::parser::OmpClause::Release>(
128800c511b3SNimish Mishra                      &ompMemoryOrderClause->v.u)) {
128900c511b3SNimish Mishra         memory_order = mlir::omp::ClauseMemoryOrderKindAttr::get(
129000c511b3SNimish Mishra             firOpBuilder.getContext(), omp::ClauseMemoryOrderKind::Release);
129100c511b3SNimish Mishra       }
129200c511b3SNimish Mishra     }
129300c511b3SNimish Mishra   }
129400c511b3SNimish Mishra }
129500c511b3SNimish Mishra 
genOmpAtomicUpdateStatement(Fortran::lower::AbstractConverter & converter,Fortran::lower::pft::Evaluation & eval,const Fortran::parser::Variable & assignmentStmtVariable,const Fortran::parser::Expr & assignmentStmtExpr,const Fortran::parser::OmpAtomicClauseList * leftHandClauseList,const Fortran::parser::OmpAtomicClauseList * rightHandClauseList)1296a56b76d9SNimish Mishra static void genOmpAtomicUpdateStatement(
1297a56b76d9SNimish Mishra     Fortran::lower::AbstractConverter &converter,
1298a56b76d9SNimish Mishra     Fortran::lower::pft::Evaluation &eval,
1299a56b76d9SNimish Mishra     const Fortran::parser::Variable &assignmentStmtVariable,
1300a56b76d9SNimish Mishra     const Fortran::parser::Expr &assignmentStmtExpr,
1301a56b76d9SNimish Mishra     const Fortran::parser::OmpAtomicClauseList *leftHandClauseList,
1302a56b76d9SNimish Mishra     const Fortran::parser::OmpAtomicClauseList *rightHandClauseList) {
1303a56b76d9SNimish Mishra   // Generate `omp.atomic.update` operation for atomic assignment statements
1304a56b76d9SNimish Mishra   auto &firOpBuilder = converter.getFirOpBuilder();
1305a56b76d9SNimish Mishra   auto currentLocation = converter.getCurrentLocation();
1306a56b76d9SNimish Mishra   Fortran::lower::StatementContext stmtCtx;
1307a56b76d9SNimish Mishra 
1308a56b76d9SNimish Mishra   mlir::Value address = fir::getBase(converter.genExprAddr(
1309a56b76d9SNimish Mishra       *Fortran::semantics::GetExpr(assignmentStmtVariable), stmtCtx));
1310a56b76d9SNimish Mishra   // If no hint clause is specified, the effect is as if
1311a56b76d9SNimish Mishra   // hint(omp_sync_hint_none) had been specified.
1312a56b76d9SNimish Mishra   mlir::IntegerAttr hint = nullptr;
1313a56b76d9SNimish Mishra   mlir::omp::ClauseMemoryOrderKindAttr memory_order = nullptr;
1314a56b76d9SNimish Mishra   if (leftHandClauseList)
1315a56b76d9SNimish Mishra     genOmpAtomicHintAndMemoryOrderClauses(converter, *leftHandClauseList, hint,
1316a56b76d9SNimish Mishra                                           memory_order);
1317a56b76d9SNimish Mishra   if (rightHandClauseList)
1318a56b76d9SNimish Mishra     genOmpAtomicHintAndMemoryOrderClauses(converter, *rightHandClauseList, hint,
1319a56b76d9SNimish Mishra                                           memory_order);
1320a56b76d9SNimish Mishra   auto atomicUpdateOp = firOpBuilder.create<mlir::omp::AtomicUpdateOp>(
1321a56b76d9SNimish Mishra       currentLocation, address, hint, memory_order);
1322a56b76d9SNimish Mishra 
1323a56b76d9SNimish Mishra   //// Generate body of Atomic Update operation
1324a56b76d9SNimish Mishra   // If an argument for the region is provided then create the block with that
1325a56b76d9SNimish Mishra   // argument. Also update the symbol's address with the argument mlir value.
1326a56b76d9SNimish Mishra   mlir::Type varType =
1327a56b76d9SNimish Mishra       fir::getBase(
1328a56b76d9SNimish Mishra           converter.genExprValue(
1329a56b76d9SNimish Mishra               *Fortran::semantics::GetExpr(assignmentStmtVariable), stmtCtx))
1330a56b76d9SNimish Mishra           .getType();
1331a56b76d9SNimish Mishra   SmallVector<Type> varTys = {varType};
1332a56b76d9SNimish Mishra   SmallVector<Location> locs = {currentLocation};
1333a56b76d9SNimish Mishra   firOpBuilder.createBlock(&atomicUpdateOp.getRegion(), {}, varTys, locs);
1334a56b76d9SNimish Mishra   mlir::Value val =
1335a56b76d9SNimish Mishra       fir::getBase(atomicUpdateOp.getRegion().front().getArgument(0));
133658753deaSNimish Mishra   auto varDesignator =
133758753deaSNimish Mishra       std::get_if<Fortran::common::Indirection<Fortran::parser::Designator>>(
133858753deaSNimish Mishra           &assignmentStmtVariable.u);
133958753deaSNimish Mishra   assert(varDesignator && "Variable designator for atomic update assignment "
134058753deaSNimish Mishra                           "statement does not exist");
134158753deaSNimish Mishra   const auto *name = getDesignatorNameIfDataRef(varDesignator->value());
134258753deaSNimish Mishra   assert(name && name->symbol &&
134358753deaSNimish Mishra          "No symbol attached to atomic update variable");
134458753deaSNimish Mishra   converter.bindSymbol(*name->symbol, val);
1345a56b76d9SNimish Mishra   // Set the insert for the terminator operation to go at the end of the
1346a56b76d9SNimish Mishra   // block.
1347a56b76d9SNimish Mishra   mlir::Block &block = atomicUpdateOp.getRegion().back();
1348a56b76d9SNimish Mishra   firOpBuilder.setInsertionPointToEnd(&block);
1349a56b76d9SNimish Mishra 
1350a56b76d9SNimish Mishra   mlir::Value result = fir::getBase(converter.genExprValue(
1351a56b76d9SNimish Mishra       *Fortran::semantics::GetExpr(assignmentStmtExpr), stmtCtx));
1352a56b76d9SNimish Mishra   // Insert the terminator: YieldOp.
1353a56b76d9SNimish Mishra   firOpBuilder.create<mlir::omp::YieldOp>(currentLocation, result);
1354a56b76d9SNimish Mishra   // Reset the insert point to before the terminator.
1355a56b76d9SNimish Mishra   firOpBuilder.setInsertionPointToStart(&block);
1356a56b76d9SNimish Mishra }
1357a56b76d9SNimish Mishra 
135800c511b3SNimish Mishra static void
genOmpAtomicWrite(Fortran::lower::AbstractConverter & converter,Fortran::lower::pft::Evaluation & eval,const Fortran::parser::OmpAtomicWrite & atomicWrite)135900c511b3SNimish Mishra genOmpAtomicWrite(Fortran::lower::AbstractConverter &converter,
136000c511b3SNimish Mishra                   Fortran::lower::pft::Evaluation &eval,
136100c511b3SNimish Mishra                   const Fortran::parser::OmpAtomicWrite &atomicWrite) {
136200c511b3SNimish Mishra   auto &firOpBuilder = converter.getFirOpBuilder();
136300c511b3SNimish Mishra   auto currentLocation = converter.getCurrentLocation();
136466073306SPeixin-Qiao   // Get the value and address of atomic write operands.
136500c511b3SNimish Mishra   const Fortran::parser::OmpAtomicClauseList &rightHandClauseList =
136600c511b3SNimish Mishra       std::get<2>(atomicWrite.t);
136700c511b3SNimish Mishra   const Fortran::parser::OmpAtomicClauseList &leftHandClauseList =
136800c511b3SNimish Mishra       std::get<0>(atomicWrite.t);
136900c511b3SNimish Mishra   const auto &assignmentStmtExpr =
137000c511b3SNimish Mishra       std::get<Fortran::parser::Expr>(std::get<3>(atomicWrite.t).statement.t);
137100c511b3SNimish Mishra   const auto &assignmentStmtVariable = std::get<Fortran::parser::Variable>(
137200c511b3SNimish Mishra       std::get<3>(atomicWrite.t).statement.t);
137300c511b3SNimish Mishra   Fortran::lower::StatementContext stmtCtx;
137466073306SPeixin-Qiao   mlir::Value value = fir::getBase(converter.genExprValue(
137500c511b3SNimish Mishra       *Fortran::semantics::GetExpr(assignmentStmtExpr), stmtCtx));
137666073306SPeixin-Qiao   mlir::Value address = fir::getBase(converter.genExprAddr(
137766073306SPeixin-Qiao       *Fortran::semantics::GetExpr(assignmentStmtVariable), stmtCtx));
137866073306SPeixin-Qiao   // If no hint clause is specified, the effect is as if
137966073306SPeixin-Qiao   // hint(omp_sync_hint_none) had been specified.
138066073306SPeixin-Qiao   mlir::IntegerAttr hint = nullptr;
138166073306SPeixin-Qiao   mlir::omp::ClauseMemoryOrderKindAttr memory_order = nullptr;
138200c511b3SNimish Mishra   genOmpAtomicHintAndMemoryOrderClauses(converter, leftHandClauseList, hint,
138300c511b3SNimish Mishra                                         memory_order);
138400c511b3SNimish Mishra   genOmpAtomicHintAndMemoryOrderClauses(converter, rightHandClauseList, hint,
138500c511b3SNimish Mishra                                         memory_order);
138600c511b3SNimish Mishra   firOpBuilder.create<mlir::omp::AtomicWriteOp>(currentLocation, address, value,
138700c511b3SNimish Mishra                                                 hint, memory_order);
138800c511b3SNimish Mishra }
138900c511b3SNimish Mishra 
genOmpAtomicRead(Fortran::lower::AbstractConverter & converter,Fortran::lower::pft::Evaluation & eval,const Fortran::parser::OmpAtomicRead & atomicRead)139000c511b3SNimish Mishra static void genOmpAtomicRead(Fortran::lower::AbstractConverter &converter,
139100c511b3SNimish Mishra                              Fortran::lower::pft::Evaluation &eval,
139200c511b3SNimish Mishra                              const Fortran::parser::OmpAtomicRead &atomicRead) {
139300c511b3SNimish Mishra   auto &firOpBuilder = converter.getFirOpBuilder();
139400c511b3SNimish Mishra   auto currentLocation = converter.getCurrentLocation();
139566073306SPeixin-Qiao   // Get the address of atomic read operands.
139600c511b3SNimish Mishra   const Fortran::parser::OmpAtomicClauseList &rightHandClauseList =
139700c511b3SNimish Mishra       std::get<2>(atomicRead.t);
139800c511b3SNimish Mishra   const Fortran::parser::OmpAtomicClauseList &leftHandClauseList =
139900c511b3SNimish Mishra       std::get<0>(atomicRead.t);
140000c511b3SNimish Mishra   const auto &assignmentStmtExpr =
140100c511b3SNimish Mishra       std::get<Fortran::parser::Expr>(std::get<3>(atomicRead.t).statement.t);
140200c511b3SNimish Mishra   const auto &assignmentStmtVariable = std::get<Fortran::parser::Variable>(
140300c511b3SNimish Mishra       std::get<3>(atomicRead.t).statement.t);
140466073306SPeixin-Qiao   Fortran::lower::StatementContext stmtCtx;
140566073306SPeixin-Qiao   mlir::Value from_address = fir::getBase(converter.genExprAddr(
140666073306SPeixin-Qiao       *Fortran::semantics::GetExpr(assignmentStmtExpr), stmtCtx));
140766073306SPeixin-Qiao   mlir::Value to_address = fir::getBase(converter.genExprAddr(
140866073306SPeixin-Qiao       *Fortran::semantics::GetExpr(assignmentStmtVariable), stmtCtx));
140966073306SPeixin-Qiao   // If no hint clause is specified, the effect is as if
141066073306SPeixin-Qiao   // hint(omp_sync_hint_none) had been specified.
141166073306SPeixin-Qiao   mlir::IntegerAttr hint = nullptr;
141266073306SPeixin-Qiao   mlir::omp::ClauseMemoryOrderKindAttr memory_order = nullptr;
141300c511b3SNimish Mishra   genOmpAtomicHintAndMemoryOrderClauses(converter, leftHandClauseList, hint,
141400c511b3SNimish Mishra                                         memory_order);
141500c511b3SNimish Mishra   genOmpAtomicHintAndMemoryOrderClauses(converter, rightHandClauseList, hint,
141600c511b3SNimish Mishra                                         memory_order);
141700c511b3SNimish Mishra   firOpBuilder.create<mlir::omp::AtomicReadOp>(currentLocation, from_address,
141800c511b3SNimish Mishra                                                to_address, hint, memory_order);
141900c511b3SNimish Mishra }
142000c511b3SNimish Mishra 
142100c511b3SNimish Mishra static void
genOmpAtomicUpdate(Fortran::lower::AbstractConverter & converter,Fortran::lower::pft::Evaluation & eval,const Fortran::parser::OmpAtomicUpdate & atomicUpdate)1422a56b76d9SNimish Mishra genOmpAtomicUpdate(Fortran::lower::AbstractConverter &converter,
1423a56b76d9SNimish Mishra                    Fortran::lower::pft::Evaluation &eval,
1424a56b76d9SNimish Mishra                    const Fortran::parser::OmpAtomicUpdate &atomicUpdate) {
1425a56b76d9SNimish Mishra   const Fortran::parser::OmpAtomicClauseList &rightHandClauseList =
1426a56b76d9SNimish Mishra       std::get<2>(atomicUpdate.t);
1427a56b76d9SNimish Mishra   const Fortran::parser::OmpAtomicClauseList &leftHandClauseList =
1428a56b76d9SNimish Mishra       std::get<0>(atomicUpdate.t);
1429a56b76d9SNimish Mishra   const auto &assignmentStmtExpr =
1430a56b76d9SNimish Mishra       std::get<Fortran::parser::Expr>(std::get<3>(atomicUpdate.t).statement.t);
1431a56b76d9SNimish Mishra   const auto &assignmentStmtVariable = std::get<Fortran::parser::Variable>(
1432a56b76d9SNimish Mishra       std::get<3>(atomicUpdate.t).statement.t);
1433a56b76d9SNimish Mishra 
1434a56b76d9SNimish Mishra   genOmpAtomicUpdateStatement(converter, eval, assignmentStmtVariable,
1435a56b76d9SNimish Mishra                               assignmentStmtExpr, &leftHandClauseList,
1436a56b76d9SNimish Mishra                               &rightHandClauseList);
1437a56b76d9SNimish Mishra }
1438a56b76d9SNimish Mishra 
genOmpAtomic(Fortran::lower::AbstractConverter & converter,Fortran::lower::pft::Evaluation & eval,const Fortran::parser::OmpAtomic & atomicConstruct)1439a56b76d9SNimish Mishra static void genOmpAtomic(Fortran::lower::AbstractConverter &converter,
1440a56b76d9SNimish Mishra                          Fortran::lower::pft::Evaluation &eval,
1441a56b76d9SNimish Mishra                          const Fortran::parser::OmpAtomic &atomicConstruct) {
1442a56b76d9SNimish Mishra   const Fortran::parser::OmpAtomicClauseList &atomicClauseList =
1443a56b76d9SNimish Mishra       std::get<Fortran::parser::OmpAtomicClauseList>(atomicConstruct.t);
1444a56b76d9SNimish Mishra   const auto &assignmentStmtExpr = std::get<Fortran::parser::Expr>(
1445a56b76d9SNimish Mishra       std::get<Fortran::parser::Statement<Fortran::parser::AssignmentStmt>>(
1446a56b76d9SNimish Mishra           atomicConstruct.t)
1447a56b76d9SNimish Mishra           .statement.t);
1448a56b76d9SNimish Mishra   const auto &assignmentStmtVariable = std::get<Fortran::parser::Variable>(
1449a56b76d9SNimish Mishra       std::get<Fortran::parser::Statement<Fortran::parser::AssignmentStmt>>(
1450a56b76d9SNimish Mishra           atomicConstruct.t)
1451a56b76d9SNimish Mishra           .statement.t);
1452a56b76d9SNimish Mishra   // If atomic-clause is not present on the construct, the behaviour is as if
1453a56b76d9SNimish Mishra   // the update clause is specified
1454a56b76d9SNimish Mishra   genOmpAtomicUpdateStatement(converter, eval, assignmentStmtVariable,
1455a56b76d9SNimish Mishra                               assignmentStmtExpr, &atomicClauseList, nullptr);
1456a56b76d9SNimish Mishra }
1457a56b76d9SNimish Mishra 
1458a56b76d9SNimish Mishra static void
genOMP(Fortran::lower::AbstractConverter & converter,Fortran::lower::pft::Evaluation & eval,const Fortran::parser::OpenMPAtomicConstruct & atomicConstruct)145900c511b3SNimish Mishra genOMP(Fortran::lower::AbstractConverter &converter,
146000c511b3SNimish Mishra        Fortran::lower::pft::Evaluation &eval,
146100c511b3SNimish Mishra        const Fortran::parser::OpenMPAtomicConstruct &atomicConstruct) {
146200c511b3SNimish Mishra   std::visit(Fortran::common::visitors{
146300c511b3SNimish Mishra                  [&](const Fortran::parser::OmpAtomicRead &atomicRead) {
146400c511b3SNimish Mishra                    genOmpAtomicRead(converter, eval, atomicRead);
146500c511b3SNimish Mishra                  },
146600c511b3SNimish Mishra                  [&](const Fortran::parser::OmpAtomicWrite &atomicWrite) {
146700c511b3SNimish Mishra                    genOmpAtomicWrite(converter, eval, atomicWrite);
146800c511b3SNimish Mishra                  },
1469a56b76d9SNimish Mishra                  [&](const Fortran::parser::OmpAtomic &atomicConstruct) {
1470a56b76d9SNimish Mishra                    genOmpAtomic(converter, eval, atomicConstruct);
1471a56b76d9SNimish Mishra                  },
1472a56b76d9SNimish Mishra                  [&](const Fortran::parser::OmpAtomicUpdate &atomicUpdate) {
1473a56b76d9SNimish Mishra                    genOmpAtomicUpdate(converter, eval, atomicUpdate);
1474a56b76d9SNimish Mishra                  },
147500c511b3SNimish Mishra                  [&](const auto &) {
1476a56b76d9SNimish Mishra                    TODO(converter.getCurrentLocation(), "Atomic capture");
147700c511b3SNimish Mishra                  },
147800c511b3SNimish Mishra              },
147900c511b3SNimish Mishra              atomicConstruct.u);
148000c511b3SNimish Mishra }
148100c511b3SNimish Mishra 
genOpenMPConstruct(Fortran::lower::AbstractConverter & converter,Fortran::lower::pft::Evaluation & eval,const Fortran::parser::OpenMPConstruct & ompConstruct)14823d0b7602SSourabh Singh Tomar void Fortran::lower::genOpenMPConstruct(
1483dfa9065aSSourabh Singh Tomar     Fortran::lower::AbstractConverter &converter,
14843d0b7602SSourabh Singh Tomar     Fortran::lower::pft::Evaluation &eval,
14853d0b7602SSourabh Singh Tomar     const Fortran::parser::OpenMPConstruct &ompConstruct) {
14863d0b7602SSourabh Singh Tomar 
14873d0b7602SSourabh Singh Tomar   std::visit(
14883d0b7602SSourabh Singh Tomar       common::visitors{
14893d0b7602SSourabh Singh Tomar           [&](const Fortran::parser::OpenMPStandaloneConstruct
14903d0b7602SSourabh Singh Tomar                   &standaloneConstruct) {
1491dfa9065aSSourabh Singh Tomar             genOMP(converter, eval, standaloneConstruct);
14923d0b7602SSourabh Singh Tomar           },
14933d0b7602SSourabh Singh Tomar           [&](const Fortran::parser::OpenMPSectionsConstruct
149436ea1cacSJean Perier                   &sectionsConstruct) {
149588d5289fSNimish Mishra             genOMP(converter, eval, sectionsConstruct);
149636ea1cacSJean Perier           },
1497ae1623b3SShraiysh Vaishay           [&](const Fortran::parser::OpenMPSectionConstruct &sectionConstruct) {
149888d5289fSNimish Mishra             genOMP(converter, eval, sectionConstruct);
1499ae1623b3SShraiysh Vaishay           },
15003d0b7602SSourabh Singh Tomar           [&](const Fortran::parser::OpenMPLoopConstruct &loopConstruct) {
1501b85c39ddSKiran Chandramohan             genOMP(converter, eval, loopConstruct);
15023d0b7602SSourabh Singh Tomar           },
1503c9e967afSIrina Dobrescu           [&](const Fortran::parser::OpenMPDeclarativeAllocate
150436ea1cacSJean Perier                   &execAllocConstruct) {
150536ea1cacSJean Perier             TODO(converter.getCurrentLocation(), "OpenMPDeclarativeAllocate");
150636ea1cacSJean Perier           },
1507c9e967afSIrina Dobrescu           [&](const Fortran::parser::OpenMPExecutableAllocate
150836ea1cacSJean Perier                   &execAllocConstruct) {
150936ea1cacSJean Perier             TODO(converter.getCurrentLocation(), "OpenMPExecutableAllocate");
151036ea1cacSJean Perier           },
15113d0b7602SSourabh Singh Tomar           [&](const Fortran::parser::OpenMPBlockConstruct &blockConstruct) {
1512dfa9065aSSourabh Singh Tomar             genOMP(converter, eval, blockConstruct);
15133d0b7602SSourabh Singh Tomar           },
15143d0b7602SSourabh Singh Tomar           [&](const Fortran::parser::OpenMPAtomicConstruct &atomicConstruct) {
151500c511b3SNimish Mishra             genOMP(converter, eval, atomicConstruct);
15163d0b7602SSourabh Singh Tomar           },
15173d0b7602SSourabh Singh Tomar           [&](const Fortran::parser::OpenMPCriticalConstruct
151836ea1cacSJean Perier                   &criticalConstruct) {
1519ebec5e5cSShraiysh Vaishay             genOMP(converter, eval, criticalConstruct);
152036ea1cacSJean Perier           },
15213d0b7602SSourabh Singh Tomar       },
15223d0b7602SSourabh Singh Tomar       ompConstruct.u);
1523ae6e499dSEric Schweitz }
1524b6b8d345SPeixin-Qiao 
genThreadprivateOp(Fortran::lower::AbstractConverter & converter,const Fortran::lower::pft::Variable & var)1525411bd2d4SPeixin-Qiao void Fortran::lower::genThreadprivateOp(
1526411bd2d4SPeixin-Qiao     Fortran::lower::AbstractConverter &converter,
1527411bd2d4SPeixin-Qiao     const Fortran::lower::pft::Variable &var) {
1528411bd2d4SPeixin-Qiao   fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();
1529411bd2d4SPeixin-Qiao   mlir::Location currentLocation = converter.getCurrentLocation();
1530411bd2d4SPeixin-Qiao 
1531411bd2d4SPeixin-Qiao   const Fortran::semantics::Symbol &sym = var.getSymbol();
1532411bd2d4SPeixin-Qiao   mlir::Value symThreadprivateValue;
1533411bd2d4SPeixin-Qiao   if (const Fortran::semantics::Symbol *common =
1534411bd2d4SPeixin-Qiao           Fortran::semantics::FindCommonBlockContaining(sym.GetUltimate())) {
1535411bd2d4SPeixin-Qiao     mlir::Value commonValue = converter.getSymbolAddress(*common);
1536411bd2d4SPeixin-Qiao     if (mlir::isa<mlir::omp::ThreadprivateOp>(commonValue.getDefiningOp())) {
1537411bd2d4SPeixin-Qiao       // Generate ThreadprivateOp for a common block instead of its members and
1538411bd2d4SPeixin-Qiao       // only do it once for a common block.
1539411bd2d4SPeixin-Qiao       return;
1540411bd2d4SPeixin-Qiao     }
1541411bd2d4SPeixin-Qiao     // Generate ThreadprivateOp and rebind the common block.
1542411bd2d4SPeixin-Qiao     mlir::Value commonThreadprivateValue =
1543411bd2d4SPeixin-Qiao         firOpBuilder.create<mlir::omp::ThreadprivateOp>(
1544411bd2d4SPeixin-Qiao             currentLocation, commonValue.getType(), commonValue);
1545411bd2d4SPeixin-Qiao     converter.bindSymbol(*common, commonThreadprivateValue);
1546411bd2d4SPeixin-Qiao     // Generate the threadprivate value for the common block member.
1547411bd2d4SPeixin-Qiao     symThreadprivateValue =
1548411bd2d4SPeixin-Qiao         genCommonBlockMember(converter, sym, commonThreadprivateValue);
1549411bd2d4SPeixin-Qiao   } else {
1550411bd2d4SPeixin-Qiao     mlir::Value symValue = converter.getSymbolAddress(sym);
1551411bd2d4SPeixin-Qiao     symThreadprivateValue = firOpBuilder.create<mlir::omp::ThreadprivateOp>(
1552411bd2d4SPeixin-Qiao         currentLocation, symValue.getType(), symValue);
1553411bd2d4SPeixin-Qiao   }
1554411bd2d4SPeixin-Qiao 
1555411bd2d4SPeixin-Qiao   fir::ExtendedValue sexv = converter.getSymbolExtendedValue(sym);
1556411bd2d4SPeixin-Qiao   fir::ExtendedValue symThreadprivateExv =
1557411bd2d4SPeixin-Qiao       getExtendedValue(sexv, symThreadprivateValue);
1558411bd2d4SPeixin-Qiao   converter.bindSymbol(sym, symThreadprivateExv);
1559411bd2d4SPeixin-Qiao }
1560411bd2d4SPeixin-Qiao 
genOpenMPDeclarativeConstruct(Fortran::lower::AbstractConverter & converter,Fortran::lower::pft::Evaluation & eval,const Fortran::parser::OpenMPDeclarativeConstruct & ompDeclConstruct)1561b6b8d345SPeixin-Qiao void Fortran::lower::genOpenMPDeclarativeConstruct(
1562b6b8d345SPeixin-Qiao     Fortran::lower::AbstractConverter &converter,
1563b6b8d345SPeixin-Qiao     Fortran::lower::pft::Evaluation &eval,
1564b6b8d345SPeixin-Qiao     const Fortran::parser::OpenMPDeclarativeConstruct &ompDeclConstruct) {
1565b6b8d345SPeixin-Qiao 
1566b6b8d345SPeixin-Qiao   std::visit(
1567b6b8d345SPeixin-Qiao       common::visitors{
1568b6b8d345SPeixin-Qiao           [&](const Fortran::parser::OpenMPDeclarativeAllocate
1569b6b8d345SPeixin-Qiao                   &declarativeAllocate) {
1570b6b8d345SPeixin-Qiao             TODO(converter.getCurrentLocation(), "OpenMPDeclarativeAllocate");
1571b6b8d345SPeixin-Qiao           },
1572b6b8d345SPeixin-Qiao           [&](const Fortran::parser::OpenMPDeclareReductionConstruct
1573b6b8d345SPeixin-Qiao                   &declareReductionConstruct) {
1574b6b8d345SPeixin-Qiao             TODO(converter.getCurrentLocation(),
1575b6b8d345SPeixin-Qiao                  "OpenMPDeclareReductionConstruct");
1576b6b8d345SPeixin-Qiao           },
1577b6b8d345SPeixin-Qiao           [&](const Fortran::parser::OpenMPDeclareSimdConstruct
1578b6b8d345SPeixin-Qiao                   &declareSimdConstruct) {
1579b6b8d345SPeixin-Qiao             TODO(converter.getCurrentLocation(), "OpenMPDeclareSimdConstruct");
1580b6b8d345SPeixin-Qiao           },
1581b6b8d345SPeixin-Qiao           [&](const Fortran::parser::OpenMPDeclareTargetConstruct
1582b6b8d345SPeixin-Qiao                   &declareTargetConstruct) {
1583b6b8d345SPeixin-Qiao             TODO(converter.getCurrentLocation(),
1584b6b8d345SPeixin-Qiao                  "OpenMPDeclareTargetConstruct");
1585b6b8d345SPeixin-Qiao           },
1586b6b8d345SPeixin-Qiao           [&](const Fortran::parser::OpenMPThreadprivate &threadprivate) {
1587411bd2d4SPeixin-Qiao             // The directive is lowered when instantiating the variable to
1588411bd2d4SPeixin-Qiao             // support the case of threadprivate variable declared in module.
1589b6b8d345SPeixin-Qiao           },
1590b6b8d345SPeixin-Qiao       },
1591b6b8d345SPeixin-Qiao       ompDeclConstruct.u);
1592b6b8d345SPeixin-Qiao }
15937bb1151bSKiran Chandramohan 
15947bb1151bSKiran Chandramohan // Generate an OpenMP reduction operation. This implementation finds the chain :
15957bb1151bSKiran Chandramohan // load reduction var -> reduction_operation -> store reduction var and replaces
15967bb1151bSKiran Chandramohan // it with the reduction operation.
15977bb1151bSKiran Chandramohan // TODO: Currently assumes it is an integer addition reduction. Generalize this
15987bb1151bSKiran Chandramohan // for various reduction operation types.
15997bb1151bSKiran Chandramohan // TODO: Generate the reduction operation during lowering instead of creating
16007bb1151bSKiran Chandramohan // and removing operations since this is not a robust approach. Also, removing
16017bb1151bSKiran Chandramohan // ops in the builder (instead of a rewriter) is probably not the best approach.
genOpenMPReduction(Fortran::lower::AbstractConverter & converter,const Fortran::parser::OmpClauseList & clauseList)16027bb1151bSKiran Chandramohan void Fortran::lower::genOpenMPReduction(
16037bb1151bSKiran Chandramohan     Fortran::lower::AbstractConverter &converter,
16047bb1151bSKiran Chandramohan     const Fortran::parser::OmpClauseList &clauseList) {
16057bb1151bSKiran Chandramohan   fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();
16067bb1151bSKiran Chandramohan 
16077bb1151bSKiran Chandramohan   for (const auto &clause : clauseList.v) {
16087bb1151bSKiran Chandramohan     if (const auto &reductionClause =
16097bb1151bSKiran Chandramohan             std::get_if<Fortran::parser::OmpClause::Reduction>(&clause.u)) {
16107bb1151bSKiran Chandramohan       const auto &redOperator{std::get<Fortran::parser::OmpReductionOperator>(
16117bb1151bSKiran Chandramohan           reductionClause->v.t)};
16127bb1151bSKiran Chandramohan       const auto &objectList{
16137bb1151bSKiran Chandramohan           std::get<Fortran::parser::OmpObjectList>(reductionClause->v.t)};
16147bb1151bSKiran Chandramohan       if (auto reductionOp =
16157bb1151bSKiran Chandramohan               std::get_if<Fortran::parser::DefinedOperator>(&redOperator.u)) {
16167bb1151bSKiran Chandramohan         const auto &intrinsicOp{
16177bb1151bSKiran Chandramohan             std::get<Fortran::parser::DefinedOperator::IntrinsicOperator>(
16187bb1151bSKiran Chandramohan                 reductionOp->u)};
16197bb1151bSKiran Chandramohan         if (intrinsicOp !=
16207bb1151bSKiran Chandramohan             Fortran::parser::DefinedOperator::IntrinsicOperator::Add)
16217bb1151bSKiran Chandramohan           continue;
16227bb1151bSKiran Chandramohan         for (const auto &ompObject : objectList.v) {
16237bb1151bSKiran Chandramohan           if (const auto *name{
16247bb1151bSKiran Chandramohan                   Fortran::parser::Unwrap<Fortran::parser::Name>(ompObject)}) {
16257bb1151bSKiran Chandramohan             if (const auto *symbol{name->symbol}) {
16267bb1151bSKiran Chandramohan               mlir::Value symVal = converter.getSymbolAddress(*symbol);
16277bb1151bSKiran Chandramohan               mlir::Type redType =
16287bb1151bSKiran Chandramohan                   symVal.getType().cast<fir::ReferenceType>().getEleTy();
16297bb1151bSKiran Chandramohan               if (!redType.isIntOrIndex())
16307bb1151bSKiran Chandramohan                 continue;
16317bb1151bSKiran Chandramohan               for (mlir::OpOperand &use1 : symVal.getUses()) {
16327bb1151bSKiran Chandramohan                 if (auto load = mlir::dyn_cast<fir::LoadOp>(use1.getOwner())) {
16337bb1151bSKiran Chandramohan                   mlir::Value loadVal = load.getRes();
16347bb1151bSKiran Chandramohan                   for (mlir::OpOperand &use2 : loadVal.getUses()) {
16357bb1151bSKiran Chandramohan                     if (auto add = mlir::dyn_cast<mlir::arith::AddIOp>(
16367bb1151bSKiran Chandramohan                             use2.getOwner())) {
16377bb1151bSKiran Chandramohan                       mlir::Value addRes = add.getResult();
16387bb1151bSKiran Chandramohan                       for (mlir::OpOperand &use3 : addRes.getUses()) {
16397bb1151bSKiran Chandramohan                         if (auto store =
16407bb1151bSKiran Chandramohan                                 mlir::dyn_cast<fir::StoreOp>(use3.getOwner())) {
16417bb1151bSKiran Chandramohan                           if (store.getMemref() == symVal) {
16427bb1151bSKiran Chandramohan                             // Chain found! Now replace load->reduction->store
16437bb1151bSKiran Chandramohan                             // with the OpenMP reduction operation.
16447bb1151bSKiran Chandramohan                             mlir::OpBuilder::InsertPoint insertPtDel =
16457bb1151bSKiran Chandramohan                                 firOpBuilder.saveInsertionPoint();
16467bb1151bSKiran Chandramohan                             firOpBuilder.setInsertionPoint(add);
16477bb1151bSKiran Chandramohan                             if (add.getLhs() == loadVal) {
16487bb1151bSKiran Chandramohan                               firOpBuilder.create<mlir::omp::ReductionOp>(
16497bb1151bSKiran Chandramohan                                   add.getLoc(), add.getRhs(), symVal);
16507bb1151bSKiran Chandramohan                             } else {
16517bb1151bSKiran Chandramohan                               firOpBuilder.create<mlir::omp::ReductionOp>(
16527bb1151bSKiran Chandramohan                                   add.getLoc(), add.getLhs(), symVal);
16537bb1151bSKiran Chandramohan                             }
16547bb1151bSKiran Chandramohan                             store.erase();
16557bb1151bSKiran Chandramohan                             add.erase();
16567bb1151bSKiran Chandramohan                             load.erase();
16577bb1151bSKiran Chandramohan                             firOpBuilder.restoreInsertionPoint(insertPtDel);
16587bb1151bSKiran Chandramohan                           }
16597bb1151bSKiran Chandramohan                         }
16607bb1151bSKiran Chandramohan                       }
16617bb1151bSKiran Chandramohan                     }
16627bb1151bSKiran Chandramohan                   }
16637bb1151bSKiran Chandramohan                 }
16647bb1151bSKiran Chandramohan               }
16657bb1151bSKiran Chandramohan             }
16667bb1151bSKiran Chandramohan           }
16677bb1151bSKiran Chandramohan         }
16687bb1151bSKiran Chandramohan       }
16697bb1151bSKiran Chandramohan     }
16707bb1151bSKiran Chandramohan   }
16717bb1151bSKiran Chandramohan }
1672