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/Lower/Bridge.h"
15 #include "flang/Lower/FIRBuilder.h"
16 #include "flang/Lower/PFTBuilder.h"
17 #include "flang/Parser/parse-tree.h"
18 #include "flang/Semantics/tools.h"
19 #include "mlir/Dialect/OpenMP/OpenMPDialect.h"
20 #include "llvm/Frontend/OpenMP/OMPConstants.h"
21 
22 #define TODO() llvm_unreachable("not yet implemented")
23 
24 static void genOMP(Fortran::lower::AbstractConverter &converter,
25                    Fortran::lower::pft::Evaluation &eval,
26                    const Fortran::parser::OpenMPSimpleStandaloneConstruct
27                        &simpleStandaloneConstruct) {
28   const auto &directive =
29       std::get<Fortran::parser::OmpSimpleStandaloneDirective>(
30           simpleStandaloneConstruct.t);
31   switch (directive.v) {
32   default:
33     break;
34   case llvm::omp::Directive::OMPD_barrier:
35     converter.getFirOpBuilder().create<mlir::omp::BarrierOp>(
36         converter.getCurrentLocation());
37     break;
38   case llvm::omp::Directive::OMPD_taskwait:
39     converter.getFirOpBuilder().create<mlir::omp::TaskwaitOp>(
40         converter.getCurrentLocation());
41     break;
42   case llvm::omp::Directive::OMPD_taskyield:
43     converter.getFirOpBuilder().create<mlir::omp::TaskyieldOp>(
44         converter.getCurrentLocation());
45     break;
46   case llvm::omp::Directive::OMPD_target_enter_data:
47     TODO();
48   case llvm::omp::Directive::OMPD_target_exit_data:
49     TODO();
50   case llvm::omp::Directive::OMPD_target_update:
51     TODO();
52   case llvm::omp::Directive::OMPD_ordered:
53     TODO();
54   }
55 }
56 
57 static void
58 genOMP(Fortran::lower::AbstractConverter &converter,
59        Fortran::lower::pft::Evaluation &eval,
60        const Fortran::parser::OpenMPStandaloneConstruct &standaloneConstruct) {
61   std::visit(
62       Fortran::common::visitors{
63           [&](const Fortran::parser::OpenMPSimpleStandaloneConstruct
64                   &simpleStandaloneConstruct) {
65             genOMP(converter, eval, simpleStandaloneConstruct);
66           },
67           [&](const Fortran::parser::OpenMPFlushConstruct &flushConstruct) {
68             TODO();
69           },
70           [&](const Fortran::parser::OpenMPCancelConstruct &cancelConstruct) {
71             TODO();
72           },
73           [&](const Fortran::parser::OpenMPCancellationPointConstruct
74                   &cancellationPointConstruct) { TODO(); },
75       },
76       standaloneConstruct.u);
77 }
78 
79 static void
80 genOMP(Fortran::lower::AbstractConverter &converter,
81        Fortran::lower::pft::Evaluation &eval,
82        const Fortran::parser::OpenMPBlockConstruct &blockConstruct) {
83   const auto &blockDirective =
84       std::get<Fortran::parser::OmpBeginBlockDirective>(blockConstruct.t);
85   const auto &parallelDirective =
86       std::get<Fortran::parser::OmpBlockDirective>(blockDirective.t);
87   if (parallelDirective.v == llvm::omp::OMPD_parallel) {
88     auto &firOpBuilder = converter.getFirOpBuilder();
89     auto currentLocation = converter.getCurrentLocation();
90 
91     // Clauses.
92     // FIXME: Add support for other clauses.
93     mlir::Value numThreads;
94 
95     const auto &parallelOpClauseList =
96         std::get<Fortran::parser::OmpClauseList>(blockDirective.t);
97     for (const auto &clause : parallelOpClauseList.v) {
98       if (const auto &numThreadsClause =
99               std::get_if<Fortran::parser::OmpClause::NumThreads>(&clause.u)) {
100         // OMPIRBuilder expects `NUM_THREAD` clause as a `Value`.
101         numThreads = converter.genExprValue(
102             *Fortran::semantics::GetExpr(numThreadsClause->v));
103       }
104     }
105     llvm::ArrayRef<mlir::Type> argTy;
106     Attribute defaultValue, procBindValue;
107     // Create and insert the operation.
108     // Create the Op with empty ranges for clauses that are yet to be lowered.
109     auto parallelOp = firOpBuilder.create<mlir::omp::ParallelOp>(
110         currentLocation, argTy, Value(), numThreads,
111         defaultValue.dyn_cast_or_null<StringAttr>(), ValueRange(), ValueRange(),
112         ValueRange(), ValueRange(), ValueRange(), ValueRange(),
113         procBindValue.dyn_cast_or_null<StringAttr>());
114     firOpBuilder.createBlock(&parallelOp.getRegion());
115     auto &block = parallelOp.getRegion().back();
116     firOpBuilder.setInsertionPointToStart(&block);
117     // Ensure the block is well-formed.
118     firOpBuilder.create<mlir::omp::TerminatorOp>(currentLocation);
119 
120     // Place the insertion point to the start of the first block.
121     firOpBuilder.setInsertionPointToStart(&block);
122   }
123 }
124 
125 void Fortran::lower::genOpenMPConstruct(
126     Fortran::lower::AbstractConverter &converter,
127     Fortran::lower::pft::Evaluation &eval,
128     const Fortran::parser::OpenMPConstruct &ompConstruct) {
129 
130   std::visit(
131       common::visitors{
132           [&](const Fortran::parser::OpenMPStandaloneConstruct
133                   &standaloneConstruct) {
134             genOMP(converter, eval, standaloneConstruct);
135           },
136           [&](const Fortran::parser::OpenMPSectionsConstruct
137                   &sectionsConstruct) { TODO(); },
138           [&](const Fortran::parser::OpenMPLoopConstruct &loopConstruct) {
139             TODO();
140           },
141           [&](const Fortran::parser::OpenMPBlockConstruct &blockConstruct) {
142             genOMP(converter, eval, blockConstruct);
143           },
144           [&](const Fortran::parser::OpenMPAtomicConstruct &atomicConstruct) {
145             TODO();
146           },
147           [&](const Fortran::parser::OpenMPCriticalConstruct
148                   &criticalConstruct) { TODO(); },
149       },
150       ompConstruct.u);
151 }
152 
153 void Fortran::lower::genOpenMPEndLoop(
154     Fortran::lower::AbstractConverter &, Fortran::lower::pft::Evaluation &,
155     const Fortran::parser::OmpEndLoopDirective &) {
156   TODO();
157 }
158