1 //===-- Runtime.cpp -------------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "flang/Lower/Runtime.h"
10 #include "flang/Lower/Bridge.h"
11 #include "flang/Lower/OpenACC.h"
12 #include "flang/Lower/OpenMP.h"
13 #include "flang/Lower/StatementContext.h"
14 #include "flang/Optimizer/Builder/FIRBuilder.h"
15 #include "flang/Optimizer/Builder/Runtime/RTBuilder.h"
16 #include "flang/Optimizer/Builder/Todo.h"
17 #include "flang/Optimizer/Dialect/FIROpsSupport.h"
18 #include "flang/Parser/parse-tree.h"
19 #include "flang/Runtime/misc-intrinsic.h"
20 #include "flang/Runtime/pointer.h"
21 #include "flang/Runtime/random.h"
22 #include "flang/Runtime/stop.h"
23 #include "flang/Runtime/time-intrinsic.h"
24 #include "flang/Semantics/tools.h"
25 #include "mlir/Dialect/OpenACC/OpenACC.h"
26 #include "mlir/Dialect/OpenMP/OpenMPDialect.h"
27 #include "llvm/Support/Debug.h"
30 #define DEBUG_TYPE "flang-lower-runtime"
32 using namespace Fortran::runtime
;
34 /// Runtime calls that do not return to the caller indicate this condition by
35 /// terminating the current basic block with an unreachable op.
36 static void genUnreachable(fir::FirOpBuilder
&builder
, mlir::Location loc
) {
37 mlir::Block
*curBlock
= builder
.getBlock();
38 mlir::Operation
*parentOp
= curBlock
->getParentOp();
39 if (parentOp
->getDialect()->getNamespace() ==
40 mlir::omp::OpenMPDialect::getDialectNamespace())
41 Fortran::lower::genOpenMPTerminator(builder
, parentOp
, loc
);
42 else if (parentOp
->getDialect()->getNamespace() ==
43 mlir::acc::OpenACCDialect::getDialectNamespace())
44 Fortran::lower::genOpenACCTerminator(builder
, parentOp
, loc
);
46 builder
.create
<fir::UnreachableOp
>(loc
);
47 mlir::Block
*newBlock
= curBlock
->splitBlock(builder
.getInsertionPoint());
48 builder
.setInsertionPointToStart(newBlock
);
51 //===----------------------------------------------------------------------===//
52 // Misc. Fortran statements that lower to runtime calls
53 //===----------------------------------------------------------------------===//
55 void Fortran::lower::genStopStatement(
56 Fortran::lower::AbstractConverter
&converter
,
57 const Fortran::parser::StopStmt
&stmt
) {
58 fir::FirOpBuilder
&builder
= converter
.getFirOpBuilder();
59 mlir::Location loc
= converter
.getCurrentLocation();
60 Fortran::lower::StatementContext stmtCtx
;
61 llvm::SmallVector
<mlir::Value
> operands
;
62 mlir::func::FuncOp callee
;
63 mlir::FunctionType calleeType
;
64 // First operand is stop code (zero if absent)
65 if (const auto &code
=
66 std::get
<std::optional
<Fortran::parser::StopCode
>>(stmt
.t
)) {
68 converter
.genExprValue(*Fortran::semantics::GetExpr(*code
), stmtCtx
);
69 LLVM_DEBUG(llvm::dbgs() << "stop expression: "; expr
.dump();
70 llvm::dbgs() << '\n');
72 [&](const fir::CharBoxValue
&x
) {
73 callee
= fir::runtime::getRuntimeFunc
<mkRTKey(StopStatementText
)>(
75 calleeType
= callee
.getFunctionType();
76 // Creates a pair of operands for the CHARACTER and its LEN.
78 builder
.createConvert(loc
, calleeType
.getInput(0), x
.getAddr()));
80 builder
.createConvert(loc
, calleeType
.getInput(1), x
.getLen()));
82 [&](fir::UnboxedValue x
) {
83 callee
= fir::runtime::getRuntimeFunc
<mkRTKey(StopStatement
)>(
85 calleeType
= callee
.getFunctionType();
87 builder
.createConvert(loc
, calleeType
.getInput(0), x
);
88 operands
.push_back(cast
);
91 mlir::emitError(loc
, "unhandled expression in STOP");
95 callee
= fir::runtime::getRuntimeFunc
<mkRTKey(StopStatement
)>(loc
, builder
);
96 calleeType
= callee
.getFunctionType();
98 builder
.createIntegerConstant(loc
, calleeType
.getInput(0), 0));
101 // Second operand indicates ERROR STOP
102 bool isError
= std::get
<Fortran::parser::StopStmt::Kind
>(stmt
.t
) ==
103 Fortran::parser::StopStmt::Kind::ErrorStop
;
104 operands
.push_back(builder
.createIntegerConstant(
105 loc
, calleeType
.getInput(operands
.size()), isError
));
107 // Third operand indicates QUIET (default to false).
108 if (const auto &quiet
=
109 std::get
<std::optional
<Fortran::parser::ScalarLogicalExpr
>>(stmt
.t
)) {
110 const SomeExpr
*expr
= Fortran::semantics::GetExpr(*quiet
);
111 assert(expr
&& "failed getting typed expression");
112 mlir::Value q
= fir::getBase(converter
.genExprValue(*expr
, stmtCtx
));
114 builder
.createConvert(loc
, calleeType
.getInput(operands
.size()), q
));
116 operands
.push_back(builder
.createIntegerConstant(
117 loc
, calleeType
.getInput(operands
.size()), 0));
120 builder
.create
<fir::CallOp
>(loc
, callee
, operands
);
121 auto blockIsUnterminated
= [&builder
]() {
122 mlir::Block
*currentBlock
= builder
.getBlock();
123 return currentBlock
->empty() ||
124 !currentBlock
->back().hasTrait
<mlir::OpTrait::IsTerminator
>();
126 if (blockIsUnterminated())
127 genUnreachable(builder
, loc
);
130 void Fortran::lower::genFailImageStatement(
131 Fortran::lower::AbstractConverter
&converter
) {
132 fir::FirOpBuilder
&builder
= converter
.getFirOpBuilder();
133 mlir::Location loc
= converter
.getCurrentLocation();
134 mlir::func::FuncOp callee
=
135 fir::runtime::getRuntimeFunc
<mkRTKey(FailImageStatement
)>(loc
, builder
);
136 builder
.create
<fir::CallOp
>(loc
, callee
, std::nullopt
);
137 genUnreachable(builder
, loc
);
140 void Fortran::lower::genNotifyWaitStatement(
141 Fortran::lower::AbstractConverter
&converter
,
142 const Fortran::parser::NotifyWaitStmt
&) {
143 TODO(converter
.getCurrentLocation(), "coarray: NOTIFY WAIT runtime");
146 void Fortran::lower::genEventPostStatement(
147 Fortran::lower::AbstractConverter
&converter
,
148 const Fortran::parser::EventPostStmt
&) {
149 TODO(converter
.getCurrentLocation(), "coarray: EVENT POST runtime");
152 void Fortran::lower::genEventWaitStatement(
153 Fortran::lower::AbstractConverter
&converter
,
154 const Fortran::parser::EventWaitStmt
&) {
155 TODO(converter
.getCurrentLocation(), "coarray: EVENT WAIT runtime");
158 void Fortran::lower::genLockStatement(
159 Fortran::lower::AbstractConverter
&converter
,
160 const Fortran::parser::LockStmt
&) {
161 TODO(converter
.getCurrentLocation(), "coarray: LOCK runtime");
164 void Fortran::lower::genUnlockStatement(
165 Fortran::lower::AbstractConverter
&converter
,
166 const Fortran::parser::UnlockStmt
&) {
167 TODO(converter
.getCurrentLocation(), "coarray: UNLOCK runtime");
170 void Fortran::lower::genSyncAllStatement(
171 Fortran::lower::AbstractConverter
&converter
,
172 const Fortran::parser::SyncAllStmt
&) {
173 TODO(converter
.getCurrentLocation(), "coarray: SYNC ALL runtime");
176 void Fortran::lower::genSyncImagesStatement(
177 Fortran::lower::AbstractConverter
&converter
,
178 const Fortran::parser::SyncImagesStmt
&) {
179 TODO(converter
.getCurrentLocation(), "coarray: SYNC IMAGES runtime");
182 void Fortran::lower::genSyncMemoryStatement(
183 Fortran::lower::AbstractConverter
&converter
,
184 const Fortran::parser::SyncMemoryStmt
&) {
185 TODO(converter
.getCurrentLocation(), "coarray: SYNC MEMORY runtime");
188 void Fortran::lower::genSyncTeamStatement(
189 Fortran::lower::AbstractConverter
&converter
,
190 const Fortran::parser::SyncTeamStmt
&) {
191 TODO(converter
.getCurrentLocation(), "coarray: SYNC TEAM runtime");
194 void Fortran::lower::genPauseStatement(
195 Fortran::lower::AbstractConverter
&converter
,
196 const Fortran::parser::PauseStmt
&) {
197 fir::FirOpBuilder
&builder
= converter
.getFirOpBuilder();
198 mlir::Location loc
= converter
.getCurrentLocation();
199 mlir::func::FuncOp callee
=
200 fir::runtime::getRuntimeFunc
<mkRTKey(PauseStatement
)>(loc
, builder
);
201 builder
.create
<fir::CallOp
>(loc
, callee
, std::nullopt
);
204 void Fortran::lower::genPointerAssociate(fir::FirOpBuilder
&builder
,
207 mlir::Value target
) {
208 mlir::func::FuncOp func
=
209 fir::runtime::getRuntimeFunc
<mkRTKey(PointerAssociate
)>(loc
, builder
);
210 llvm::SmallVector
<mlir::Value
> args
= fir::runtime::createArguments(
211 builder
, loc
, func
.getFunctionType(), pointer
, target
);
212 builder
.create
<fir::CallOp
>(loc
, func
, args
).getResult(0);
215 void Fortran::lower::genPointerAssociateRemapping(fir::FirOpBuilder
&builder
,
219 mlir::Value bounds
) {
220 mlir::func::FuncOp func
=
221 fir::runtime::getRuntimeFunc
<mkRTKey(PointerAssociateRemapping
)>(loc
,
223 auto fTy
= func
.getFunctionType();
224 auto sourceFile
= fir::factory::locationToFilename(builder
, loc
);
226 fir::factory::locationToLineNo(builder
, loc
, fTy
.getInput(4));
227 llvm::SmallVector
<mlir::Value
> args
= fir::runtime::createArguments(
228 builder
, loc
, func
.getFunctionType(), pointer
, target
, bounds
, sourceFile
,
230 builder
.create
<fir::CallOp
>(loc
, func
, args
).getResult(0);
233 void Fortran::lower::genPointerAssociateLowerBounds(fir::FirOpBuilder
&builder
,
237 mlir::Value lbounds
) {
238 mlir::func::FuncOp func
=
239 fir::runtime::getRuntimeFunc
<mkRTKey(PointerAssociateLowerBounds
)>(
241 llvm::SmallVector
<mlir::Value
> args
= fir::runtime::createArguments(
242 builder
, loc
, func
.getFunctionType(), pointer
, target
, lbounds
);
243 builder
.create
<fir::CallOp
>(loc
, func
, args
).getResult(0);