• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===-- OpenMP.cpp -- Open MP directive lowering --------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "flang/Lower/OpenMP.h"
14 #include "flang/Common/idioms.h"
15 #include "flang/Lower/Bridge.h"
16 #include "flang/Lower/FIRBuilder.h"
17 #include "flang/Lower/PFTBuilder.h"
18 #include "flang/Lower/Support/BoxValue.h"
19 #include "flang/Lower/Todo.h"
20 #include "flang/Parser/parse-tree.h"
21 #include "flang/Semantics/tools.h"
22 #include "mlir/Dialect/OpenMP/OpenMPDialect.h"
23 #include "llvm/Frontend/OpenMP/OMPConstants.h"
24 
25 static const Fortran::parser::Name *
getDesignatorNameIfDataRef(const Fortran::parser::Designator & designator)26 getDesignatorNameIfDataRef(const Fortran::parser::Designator &designator) {
27   const auto *dataRef = std::get_if<Fortran::parser::DataRef>(&designator.u);
28   return dataRef ? std::get_if<Fortran::parser::Name>(&dataRef->u) : nullptr;
29 }
30 
genObjectList(const Fortran::parser::OmpObjectList & objectList,Fortran::lower::AbstractConverter & converter,SmallVectorImpl<Value> & operands)31 static void genObjectList(const Fortran::parser::OmpObjectList &objectList,
32                           Fortran::lower::AbstractConverter &converter,
33                           SmallVectorImpl<Value> &operands) {
34   for (const auto &ompObject : objectList.v) {
35     std::visit(
36         Fortran::common::visitors{
37             [&](const Fortran::parser::Designator &designator) {
38               if (const auto *name = getDesignatorNameIfDataRef(designator)) {
39                 const auto variable = converter.getSymbolAddress(*name->symbol);
40                 operands.push_back(variable);
41               }
42             },
43             [&](const Fortran::parser::Name &name) {
44               const auto variable = converter.getSymbolAddress(*name.symbol);
45               operands.push_back(variable);
46             }},
47         ompObject.u);
48   }
49 }
50 
51 template <typename Op>
createBodyOfOp(Op & op,Fortran::lower::FirOpBuilder & firOpBuilder,mlir::Location & loc)52 static void createBodyOfOp(Op &op, Fortran::lower::FirOpBuilder &firOpBuilder,
53                            mlir::Location &loc) {
54   firOpBuilder.createBlock(&op.getRegion());
55   auto &block = op.getRegion().back();
56   firOpBuilder.setInsertionPointToStart(&block);
57   // Ensure the block is well-formed.
58   firOpBuilder.create<mlir::omp::TerminatorOp>(loc);
59   // Reset the insertion point to the start of the first block.
60   firOpBuilder.setInsertionPointToStart(&block);
61 }
62 
genOMP(Fortran::lower::AbstractConverter & converter,Fortran::lower::pft::Evaluation & eval,const Fortran::parser::OpenMPSimpleStandaloneConstruct & simpleStandaloneConstruct)63 static void genOMP(Fortran::lower::AbstractConverter &converter,
64                    Fortran::lower::pft::Evaluation &eval,
65                    const Fortran::parser::OpenMPSimpleStandaloneConstruct
66                        &simpleStandaloneConstruct) {
67   const auto &directive =
68       std::get<Fortran::parser::OmpSimpleStandaloneDirective>(
69           simpleStandaloneConstruct.t);
70   switch (directive.v) {
71   default:
72     break;
73   case llvm::omp::Directive::OMPD_barrier:
74     converter.getFirOpBuilder().create<mlir::omp::BarrierOp>(
75         converter.getCurrentLocation());
76     break;
77   case llvm::omp::Directive::OMPD_taskwait:
78     converter.getFirOpBuilder().create<mlir::omp::TaskwaitOp>(
79         converter.getCurrentLocation());
80     break;
81   case llvm::omp::Directive::OMPD_taskyield:
82     converter.getFirOpBuilder().create<mlir::omp::TaskyieldOp>(
83         converter.getCurrentLocation());
84     break;
85   case llvm::omp::Directive::OMPD_target_enter_data:
86     TODO("");
87   case llvm::omp::Directive::OMPD_target_exit_data:
88     TODO("");
89   case llvm::omp::Directive::OMPD_target_update:
90     TODO("");
91   case llvm::omp::Directive::OMPD_ordered:
92     TODO("");
93   }
94 }
95 
96 static void
genOMP(Fortran::lower::AbstractConverter & converter,Fortran::lower::pft::Evaluation & eval,const Fortran::parser::OpenMPStandaloneConstruct & standaloneConstruct)97 genOMP(Fortran::lower::AbstractConverter &converter,
98        Fortran::lower::pft::Evaluation &eval,
99        const Fortran::parser::OpenMPStandaloneConstruct &standaloneConstruct) {
100   std::visit(
101       Fortran::common::visitors{
102           [&](const Fortran::parser::OpenMPSimpleStandaloneConstruct
103                   &simpleStandaloneConstruct) {
104             genOMP(converter, eval, simpleStandaloneConstruct);
105           },
106           [&](const Fortran::parser::OpenMPFlushConstruct &flushConstruct) {
107             SmallVector<Value, 4> operandRange;
108             if (const auto &ompObjectList =
109                     std::get<std::optional<Fortran::parser::OmpObjectList>>(
110                         flushConstruct.t))
111               genObjectList(*ompObjectList, converter, operandRange);
112             if (std::get<std::optional<Fortran::parser::OmpMemoryOrderClause>>(
113                     flushConstruct.t))
114               TODO("Handle OmpMemoryOrderClause");
115             converter.getFirOpBuilder().create<mlir::omp::FlushOp>(
116                 converter.getCurrentLocation(), operandRange);
117           },
118           [&](const Fortran::parser::OpenMPCancelConstruct &cancelConstruct) {
119             TODO("");
120           },
121           [&](const Fortran::parser::OpenMPCancellationPointConstruct
122                   &cancellationPointConstruct) { TODO(""); },
123       },
124       standaloneConstruct.u);
125 }
126 
127 static void
genOMP(Fortran::lower::AbstractConverter & converter,Fortran::lower::pft::Evaluation & eval,const Fortran::parser::OpenMPBlockConstruct & blockConstruct)128 genOMP(Fortran::lower::AbstractConverter &converter,
129        Fortran::lower::pft::Evaluation &eval,
130        const Fortran::parser::OpenMPBlockConstruct &blockConstruct) {
131   const auto &beginBlockDirective =
132       std::get<Fortran::parser::OmpBeginBlockDirective>(blockConstruct.t);
133   const auto &blockDirective =
134       std::get<Fortran::parser::OmpBlockDirective>(beginBlockDirective.t);
135 
136   auto &firOpBuilder = converter.getFirOpBuilder();
137   auto currentLocation = converter.getCurrentLocation();
138   llvm::ArrayRef<mlir::Type> argTy;
139   if (blockDirective.v == llvm::omp::OMPD_parallel) {
140 
141     mlir::Value ifClauseOperand, numThreadsClauseOperand;
142     SmallVector<Value, 4> privateClauseOperands, firstprivateClauseOperands,
143         sharedClauseOperands, copyinClauseOperands;
144     Attribute defaultClauseOperand, procBindClauseOperand;
145 
146     const auto &parallelOpClauseList =
147         std::get<Fortran::parser::OmpClauseList>(beginBlockDirective.t);
148     for (const auto &clause : parallelOpClauseList.v) {
149       if (const auto &ifClause =
150               std::get_if<Fortran::parser::OmpIfClause>(&clause.u)) {
151         auto &expr = std::get<Fortran::parser::ScalarLogicalExpr>(ifClause->t);
152         ifClauseOperand = fir::getBase(
153             converter.genExprValue(*Fortran::semantics::GetExpr(expr)));
154       } else if (const auto &numThreadsClause =
155                      std::get_if<Fortran::parser::OmpClause::NumThreads>(
156                          &clause.u)) {
157         // OMPIRBuilder expects `NUM_THREAD` clause as a `Value`.
158         numThreadsClauseOperand = fir::getBase(converter.genExprValue(
159             *Fortran::semantics::GetExpr(numThreadsClause->v)));
160       } else if (const auto &privateClause =
161                      std::get_if<Fortran::parser::OmpClause::Private>(
162                          &clause.u)) {
163         const Fortran::parser::OmpObjectList &ompObjectList = privateClause->v;
164         genObjectList(ompObjectList, converter, privateClauseOperands);
165       } else if (const auto &firstprivateClause =
166                      std::get_if<Fortran::parser::OmpClause::Firstprivate>(
167                          &clause.u)) {
168         const Fortran::parser::OmpObjectList &ompObjectList =
169             firstprivateClause->v;
170         genObjectList(ompObjectList, converter, firstprivateClauseOperands);
171       } else if (const auto &sharedClause =
172                      std::get_if<Fortran::parser::OmpClause::Shared>(
173                          &clause.u)) {
174         const Fortran::parser::OmpObjectList &ompObjectList = sharedClause->v;
175         genObjectList(ompObjectList, converter, sharedClauseOperands);
176       } else if (const auto &copyinClause =
177                      std::get_if<Fortran::parser::OmpClause::Copyin>(
178                          &clause.u)) {
179         const Fortran::parser::OmpObjectList &ompObjectList = copyinClause->v;
180         genObjectList(ompObjectList, converter, copyinClauseOperands);
181       }
182     }
183     // Create and insert the operation.
184     auto parallelOp = firOpBuilder.create<mlir::omp::ParallelOp>(
185         currentLocation, argTy, ifClauseOperand, numThreadsClauseOperand,
186         defaultClauseOperand.dyn_cast_or_null<StringAttr>(),
187         privateClauseOperands, firstprivateClauseOperands, sharedClauseOperands,
188         copyinClauseOperands, ValueRange(), ValueRange(),
189         procBindClauseOperand.dyn_cast_or_null<StringAttr>());
190     // Handle attribute based clauses.
191     for (const auto &clause : parallelOpClauseList.v) {
192       if (const auto &defaultClause =
193               std::get_if<Fortran::parser::OmpDefaultClause>(&clause.u)) {
194         switch (defaultClause->v) {
195         case Fortran::parser::OmpDefaultClause::Type::Private:
196           parallelOp.default_valAttr(firOpBuilder.getStringAttr(
197               omp::stringifyClauseDefault(omp::ClauseDefault::defprivate)));
198           break;
199         case Fortran::parser::OmpDefaultClause::Type::Firstprivate:
200           parallelOp.default_valAttr(
201               firOpBuilder.getStringAttr(omp::stringifyClauseDefault(
202                   omp::ClauseDefault::deffirstprivate)));
203           break;
204         case Fortran::parser::OmpDefaultClause::Type::Shared:
205           parallelOp.default_valAttr(firOpBuilder.getStringAttr(
206               omp::stringifyClauseDefault(omp::ClauseDefault::defshared)));
207           break;
208         case Fortran::parser::OmpDefaultClause::Type::None:
209           parallelOp.default_valAttr(firOpBuilder.getStringAttr(
210               omp::stringifyClauseDefault(omp::ClauseDefault::defnone)));
211           break;
212         }
213       }
214       if (const auto &procBindClause =
215               std::get_if<Fortran::parser::OmpProcBindClause>(&clause.u)) {
216         switch (procBindClause->v) {
217         case Fortran::parser::OmpProcBindClause::Type::Master:
218           parallelOp.proc_bind_valAttr(
219               firOpBuilder.getStringAttr(omp::stringifyClauseProcBindKind(
220                   omp::ClauseProcBindKind::master)));
221           break;
222         case Fortran::parser::OmpProcBindClause::Type::Close:
223           parallelOp.proc_bind_valAttr(
224               firOpBuilder.getStringAttr(omp::stringifyClauseProcBindKind(
225                   omp::ClauseProcBindKind::close)));
226           break;
227         case Fortran::parser::OmpProcBindClause::Type::Spread:
228           parallelOp.proc_bind_valAttr(
229               firOpBuilder.getStringAttr(omp::stringifyClauseProcBindKind(
230                   omp::ClauseProcBindKind::spread)));
231           break;
232         }
233       }
234     }
235     createBodyOfOp<omp::ParallelOp>(parallelOp, firOpBuilder, currentLocation);
236   } else if (blockDirective.v == llvm::omp::OMPD_master) {
237     auto masterOp =
238         firOpBuilder.create<mlir::omp::MasterOp>(currentLocation, argTy);
239     createBodyOfOp<omp::MasterOp>(masterOp, firOpBuilder, currentLocation);
240   }
241 }
242 
genOpenMPConstruct(Fortran::lower::AbstractConverter & converter,Fortran::lower::pft::Evaluation & eval,const Fortran::parser::OpenMPConstruct & ompConstruct)243 void Fortran::lower::genOpenMPConstruct(
244     Fortran::lower::AbstractConverter &converter,
245     Fortran::lower::pft::Evaluation &eval,
246     const Fortran::parser::OpenMPConstruct &ompConstruct) {
247 
248   std::visit(
249       common::visitors{
250           [&](const Fortran::parser::OpenMPStandaloneConstruct
251                   &standaloneConstruct) {
252             genOMP(converter, eval, standaloneConstruct);
253           },
254           [&](const Fortran::parser::OpenMPSectionsConstruct
255                   &sectionsConstruct) { TODO(""); },
256           [&](const Fortran::parser::OpenMPLoopConstruct &loopConstruct) {
257             TODO("");
258           },
259           [&](const Fortran::parser::OpenMPBlockConstruct &blockConstruct) {
260             genOMP(converter, eval, blockConstruct);
261           },
262           [&](const Fortran::parser::OpenMPAtomicConstruct &atomicConstruct) {
263             TODO("");
264           },
265           [&](const Fortran::parser::OpenMPCriticalConstruct
266                   &criticalConstruct) { TODO(""); },
267       },
268       ompConstruct.u);
269 }
270 
genOpenMPEndLoop(Fortran::lower::AbstractConverter &,Fortran::lower::pft::Evaluation &,const Fortran::parser::OmpEndLoopDirective &)271 void Fortran::lower::genOpenMPEndLoop(
272     Fortran::lower::AbstractConverter &, Fortran::lower::pft::Evaluation &,
273     const Fortran::parser::OmpEndLoopDirective &) {
274   TODO("");
275 }
276