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 "mlir/Dialect/OpenMP/OpenMPDialect.h"
19 #include "llvm/Frontend/OpenMP/OMPConstants.h"
20 
21 #define TODO() llvm_unreachable("not yet implemented")
22 
23 static void genOMP(Fortran::lower::AbstractConverter &absConv,
24                    Fortran::lower::pft::Evaluation &eval,
25                    const Fortran::parser::OpenMPSimpleStandaloneConstruct
26                        &simpleStandaloneConstruct) {
27   const auto &directive =
28       std::get<Fortran::parser::OmpSimpleStandaloneDirective>(
29           simpleStandaloneConstruct.t);
30   switch (directive.v) {
31   default:
32     break;
33   case llvm::omp::Directive::OMPD_barrier:
34     absConv.getFirOpBuilder().create<mlir::omp::BarrierOp>(
35         absConv.getCurrentLocation());
36     break;
37   case llvm::omp::Directive::OMPD_taskwait:
38     absConv.getFirOpBuilder().create<mlir::omp::TaskwaitOp>(
39         absConv.getCurrentLocation());
40     break;
41   case llvm::omp::Directive::OMPD_taskyield:
42     absConv.getFirOpBuilder().create<mlir::omp::TaskyieldOp>(
43         absConv.getCurrentLocation());
44     break;
45   case llvm::omp::Directive::OMPD_target_enter_data:
46     TODO();
47   case llvm::omp::Directive::OMPD_target_exit_data:
48     TODO();
49   case llvm::omp::Directive::OMPD_target_update:
50     TODO();
51   case llvm::omp::Directive::OMPD_ordered:
52     TODO();
53   }
54 }
55 
56 static void
57 genOMP(Fortran::lower::AbstractConverter &absConv,
58        Fortran::lower::pft::Evaluation &eval,
59        const Fortran::parser::OpenMPStandaloneConstruct &standaloneConstruct) {
60   std::visit(
61       Fortran::common::visitors{
62           [&](const Fortran::parser::OpenMPSimpleStandaloneConstruct
63                   &simpleStandaloneConstruct) {
64             genOMP(absConv, eval, simpleStandaloneConstruct);
65           },
66           [&](const Fortran::parser::OpenMPFlushConstruct &flushConstruct) {
67             TODO();
68           },
69           [&](const Fortran::parser::OpenMPCancelConstruct &cancelConstruct) {
70             TODO();
71           },
72           [&](const Fortran::parser::OpenMPCancellationPointConstruct
73                   &cancellationPointConstruct) { TODO(); },
74       },
75       standaloneConstruct.u);
76 }
77 
78 static void
79 genOMP(Fortran::lower::AbstractConverter &absConv,
80        Fortran::lower::pft::Evaluation &eval,
81        const Fortran::parser::OpenMPBlockConstruct &blockConstruct) {
82   const auto &blockDirective =
83       std::get<Fortran::parser::OmpBeginBlockDirective>(blockConstruct.t);
84   const auto &parallelDirective =
85       std::get<Fortran::parser::OmpBlockDirective>(blockDirective.t);
86   if (parallelDirective.v == llvm::omp::OMPD_parallel) {
87     auto &firOpBuilder = absConv.getFirOpBuilder();
88     auto currentLocation = absConv.getCurrentLocation();
89     auto insertPt = firOpBuilder.saveInsertionPoint();
90     llvm::ArrayRef<mlir::Type> argTy;
91     mlir::ValueRange range;
92     llvm::SmallVector<int32_t, 6> operandSegmentSizes(6 /*Size=*/,
93                                                       0 /*Value=*/);
94     // create and insert the operation.
95     auto parallelOp = firOpBuilder.create<mlir::omp::ParallelOp>(
96         currentLocation, argTy, range);
97     parallelOp.setAttr(mlir::omp::ParallelOp::getOperandSegmentSizeAttr(),
98                        firOpBuilder.getI32VectorAttr(operandSegmentSizes));
99     parallelOp.getRegion().push_back(new Block{});
100     auto &block = parallelOp.getRegion().back();
101     firOpBuilder.setInsertionPointToStart(&block);
102     // ensure the block is well-formed.
103     firOpBuilder.create<mlir::omp::TerminatorOp>(currentLocation);
104     firOpBuilder.restoreInsertionPoint(insertPt);
105   }
106 }
107 
108 void Fortran::lower::genOpenMPConstruct(
109     Fortran::lower::AbstractConverter &absConv,
110     Fortran::lower::pft::Evaluation &eval,
111     const Fortran::parser::OpenMPConstruct &ompConstruct) {
112 
113   std::visit(
114       common::visitors{
115           [&](const Fortran::parser::OpenMPStandaloneConstruct
116                   &standaloneConstruct) {
117             genOMP(absConv, eval, standaloneConstruct);
118           },
119           [&](const Fortran::parser::OpenMPSectionsConstruct
120                   &sectionsConstruct) { TODO(); },
121           [&](const Fortran::parser::OpenMPLoopConstruct &loopConstruct) {
122             TODO();
123           },
124           [&](const Fortran::parser::OpenMPBlockConstruct &blockConstruct) {
125             genOMP(absConv, eval, blockConstruct);
126           },
127           [&](const Fortran::parser::OpenMPAtomicConstruct &atomicConstruct) {
128             TODO();
129           },
130           [&](const Fortran::parser::OpenMPCriticalConstruct
131                   &criticalConstruct) { TODO(); },
132       },
133       ompConstruct.u);
134 }
135 
136 void Fortran::lower::genOpenMPEndLoop(
137     Fortran::lower::AbstractConverter &, Fortran::lower::pft::Evaluation &,
138     const Fortran::parser::OmpEndLoopDirective &) {
139   TODO();
140 }
141