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     auto insertPt = firOpBuilder.saveInsertionPoint();
91 
92     // Clauses.
93     // FIXME: Add support for other clauses.
94     mlir::Value numThreads;
95 
96     const auto &parallelOpClauseList =
97         std::get<Fortran::parser::OmpClauseList>(blockDirective.t);
98     for (const auto &clause : parallelOpClauseList.v) {
99       if (const auto &numThreadsClause =
100               std::get_if<Fortran::parser::OmpClause::NumThreads>(&clause.u)) {
101         // OMPIRBuilder expects `NUM_THREAD` clause as a `Value`.
102         numThreads = converter.genExprValue(
103             *Fortran::semantics::GetExpr(numThreadsClause->v));
104       }
105     }
106     llvm::ArrayRef<mlir::Type> argTy;
107     Attribute defaultValue, procBindValue;
108     // Create and insert the operation.
109     // Create the Op with empty ranges for clauses that are yet to be lowered.
110     auto parallelOp = firOpBuilder.create<mlir::omp::ParallelOp>(
111         currentLocation, argTy, Value(), numThreads,
112         defaultValue.dyn_cast_or_null<StringAttr>(), ValueRange(), ValueRange(),
113         ValueRange(), ValueRange(),
114         procBindValue.dyn_cast_or_null<StringAttr>());
115     firOpBuilder.createBlock(&parallelOp.getRegion());
116     auto &block = parallelOp.getRegion().back();
117     firOpBuilder.setInsertionPointToStart(&block);
118     // Ensure the block is well-formed.
119     firOpBuilder.create<mlir::omp::TerminatorOp>(currentLocation);
120     firOpBuilder.restoreInsertionPoint(insertPt);
121   }
122 }
123 
124 void Fortran::lower::genOpenMPConstruct(
125     Fortran::lower::AbstractConverter &converter,
126     Fortran::lower::pft::Evaluation &eval,
127     const Fortran::parser::OpenMPConstruct &ompConstruct) {
128 
129   std::visit(
130       common::visitors{
131           [&](const Fortran::parser::OpenMPStandaloneConstruct
132                   &standaloneConstruct) {
133             genOMP(converter, eval, standaloneConstruct);
134           },
135           [&](const Fortran::parser::OpenMPSectionsConstruct
136                   &sectionsConstruct) { TODO(); },
137           [&](const Fortran::parser::OpenMPLoopConstruct &loopConstruct) {
138             TODO();
139           },
140           [&](const Fortran::parser::OpenMPBlockConstruct &blockConstruct) {
141             genOMP(converter, eval, blockConstruct);
142           },
143           [&](const Fortran::parser::OpenMPAtomicConstruct &atomicConstruct) {
144             TODO();
145           },
146           [&](const Fortran::parser::OpenMPCriticalConstruct
147                   &criticalConstruct) { TODO(); },
148       },
149       ompConstruct.u);
150 }
151 
152 void Fortran::lower::genOpenMPEndLoop(
153     Fortran::lower::AbstractConverter &, Fortran::lower::pft::Evaluation &,
154     const Fortran::parser::OmpEndLoopDirective &) {
155   TODO();
156 }
157