1aab4263aSValentin Clement //===-- Runtime.cpp -------------------------------------------------------===//
2aab4263aSValentin Clement //
3aab4263aSValentin Clement // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4aab4263aSValentin Clement // See https://llvm.org/LICENSE.txt for license information.
5aab4263aSValentin Clement // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6aab4263aSValentin Clement //
7aab4263aSValentin Clement //===----------------------------------------------------------------------===//
8aab4263aSValentin Clement 
9aab4263aSValentin Clement #include "flang/Lower/Runtime.h"
10aab4263aSValentin Clement #include "flang/Lower/Bridge.h"
11d0b70a07SValentin Clement #include "flang/Lower/StatementContext.h"
12aab4263aSValentin Clement #include "flang/Lower/Todo.h"
13aab4263aSValentin Clement #include "flang/Optimizer/Builder/FIRBuilder.h"
14aab4263aSValentin Clement #include "flang/Optimizer/Builder/Runtime/RTBuilder.h"
15aab4263aSValentin Clement #include "flang/Parser/parse-tree.h"
1672276bdaSValentin Clement #include "flang/Runtime/pointer.h"
17a1918fdfSValentin Clement #include "flang/Runtime/random.h"
18aab4263aSValentin Clement #include "flang/Runtime/stop.h"
199daf5765SValentin Clement #include "flang/Runtime/time-intrinsic.h"
20aab4263aSValentin Clement #include "flang/Semantics/tools.h"
21aab4263aSValentin Clement #include "llvm/Support/Debug.h"
22aab4263aSValentin Clement 
23aab4263aSValentin Clement #define DEBUG_TYPE "flang-lower-runtime"
24aab4263aSValentin Clement 
25aab4263aSValentin Clement using namespace Fortran::runtime;
26aab4263aSValentin Clement 
27aab4263aSValentin Clement /// Runtime calls that do not return to the caller indicate this condition by
28aab4263aSValentin Clement /// terminating the current basic block with an unreachable op.
29aab4263aSValentin Clement static void genUnreachable(fir::FirOpBuilder &builder, mlir::Location loc) {
30aab4263aSValentin Clement   builder.create<fir::UnreachableOp>(loc);
31aab4263aSValentin Clement   mlir::Block *newBlock =
32aab4263aSValentin Clement       builder.getBlock()->splitBlock(builder.getInsertionPoint());
33aab4263aSValentin Clement   builder.setInsertionPointToStart(newBlock);
34aab4263aSValentin Clement }
35aab4263aSValentin Clement 
36aab4263aSValentin Clement //===----------------------------------------------------------------------===//
37aab4263aSValentin Clement // Misc. Fortran statements that lower to runtime calls
38aab4263aSValentin Clement //===----------------------------------------------------------------------===//
39aab4263aSValentin Clement 
40aab4263aSValentin Clement void Fortran::lower::genStopStatement(
41aab4263aSValentin Clement     Fortran::lower::AbstractConverter &converter,
42aab4263aSValentin Clement     const Fortran::parser::StopStmt &stmt) {
43aab4263aSValentin Clement   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
44aab4263aSValentin Clement   mlir::Location loc = converter.getCurrentLocation();
45d0b70a07SValentin Clement   Fortran::lower::StatementContext stmtCtx;
46aab4263aSValentin Clement   llvm::SmallVector<mlir::Value> operands;
47aab4263aSValentin Clement   mlir::FuncOp callee;
48aab4263aSValentin Clement   mlir::FunctionType calleeType;
49aab4263aSValentin Clement   // First operand is stop code (zero if absent)
50ca53e049SValentin Clement   if (const auto &code =
51ca53e049SValentin Clement           std::get<std::optional<Fortran::parser::StopCode>>(stmt.t)) {
52d0b70a07SValentin Clement     auto expr =
53d0b70a07SValentin Clement         converter.genExprValue(*Fortran::semantics::GetExpr(*code), stmtCtx);
54ca53e049SValentin Clement     LLVM_DEBUG(llvm::dbgs() << "stop expression: "; expr.dump();
55ca53e049SValentin Clement                llvm::dbgs() << '\n');
56ca53e049SValentin Clement     expr.match(
57ca53e049SValentin Clement         [&](const fir::CharBoxValue &x) {
58a8d48fe0SValentin Clement           callee = fir::runtime::getRuntimeFunc<mkRTKey(StopStatementText)>(
59a8d48fe0SValentin Clement               loc, builder);
60a8d48fe0SValentin Clement           calleeType = callee.getType();
61a8d48fe0SValentin Clement           // Creates a pair of operands for the CHARACTER and its LEN.
62a8d48fe0SValentin Clement           operands.push_back(
63a8d48fe0SValentin Clement               builder.createConvert(loc, calleeType.getInput(0), x.getAddr()));
64a8d48fe0SValentin Clement           operands.push_back(
65a8d48fe0SValentin Clement               builder.createConvert(loc, calleeType.getInput(1), x.getLen()));
66ca53e049SValentin Clement         },
67ca53e049SValentin Clement         [&](fir::UnboxedValue x) {
68ca53e049SValentin Clement           callee = fir::runtime::getRuntimeFunc<mkRTKey(StopStatement)>(
69ca53e049SValentin Clement               loc, builder);
70ca53e049SValentin Clement           calleeType = callee.getType();
71ca53e049SValentin Clement           mlir::Value cast =
72ca53e049SValentin Clement               builder.createConvert(loc, calleeType.getInput(0), x);
73ca53e049SValentin Clement           operands.push_back(cast);
74ca53e049SValentin Clement         },
75ca53e049SValentin Clement         [&](auto) {
76ca53e049SValentin Clement           mlir::emitError(loc, "unhandled expression in STOP");
77ca53e049SValentin Clement           std::exit(1);
78ca53e049SValentin Clement         });
79aab4263aSValentin Clement   } else {
80aab4263aSValentin Clement     callee = fir::runtime::getRuntimeFunc<mkRTKey(StopStatement)>(loc, builder);
81aab4263aSValentin Clement     calleeType = callee.getType();
82aab4263aSValentin Clement     operands.push_back(
83aab4263aSValentin Clement         builder.createIntegerConstant(loc, calleeType.getInput(0), 0));
84aab4263aSValentin Clement   }
85aab4263aSValentin Clement 
86aab4263aSValentin Clement   // Second operand indicates ERROR STOP
87aab4263aSValentin Clement   bool isError = std::get<Fortran::parser::StopStmt::Kind>(stmt.t) ==
88aab4263aSValentin Clement                  Fortran::parser::StopStmt::Kind::ErrorStop;
89aab4263aSValentin Clement   operands.push_back(builder.createIntegerConstant(
90aab4263aSValentin Clement       loc, calleeType.getInput(operands.size()), isError));
91aab4263aSValentin Clement 
92aab4263aSValentin Clement   // Third operand indicates QUIET (default to false).
93cc306740SValentin Clement   if (const auto &quiet =
94cc306740SValentin Clement           std::get<std::optional<Fortran::parser::ScalarLogicalExpr>>(stmt.t)) {
95cc306740SValentin Clement     const SomeExpr *expr = Fortran::semantics::GetExpr(*quiet);
96cc306740SValentin Clement     assert(expr && "failed getting typed expression");
97d0b70a07SValentin Clement     mlir::Value q = fir::getBase(converter.genExprValue(*expr, stmtCtx));
98cc306740SValentin Clement     operands.push_back(
99cc306740SValentin Clement         builder.createConvert(loc, calleeType.getInput(operands.size()), q));
100aab4263aSValentin Clement   } else {
101aab4263aSValentin Clement     operands.push_back(builder.createIntegerConstant(
102aab4263aSValentin Clement         loc, calleeType.getInput(operands.size()), 0));
103aab4263aSValentin Clement   }
104aab4263aSValentin Clement 
105aab4263aSValentin Clement   builder.create<fir::CallOp>(loc, callee, operands);
106aab4263aSValentin Clement   genUnreachable(builder, loc);
107aab4263aSValentin Clement }
108db01b123SValentin Clement 
109db01b123SValentin Clement void Fortran::lower::genPauseStatement(
110db01b123SValentin Clement     Fortran::lower::AbstractConverter &converter,
111db01b123SValentin Clement     const Fortran::parser::PauseStmt &) {
112db01b123SValentin Clement   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
113db01b123SValentin Clement   mlir::Location loc = converter.getCurrentLocation();
114db01b123SValentin Clement   mlir::FuncOp callee =
115db01b123SValentin Clement       fir::runtime::getRuntimeFunc<mkRTKey(PauseStatement)>(loc, builder);
116db01b123SValentin Clement   builder.create<fir::CallOp>(loc, callee, llvm::None);
117db01b123SValentin Clement }
11872276bdaSValentin Clement 
11972276bdaSValentin Clement mlir::Value Fortran::lower::genAssociated(fir::FirOpBuilder &builder,
12072276bdaSValentin Clement                                           mlir::Location loc,
12172276bdaSValentin Clement                                           mlir::Value pointer,
12272276bdaSValentin Clement                                           mlir::Value target) {
12372276bdaSValentin Clement   mlir::FuncOp func =
12472276bdaSValentin Clement       fir::runtime::getRuntimeFunc<mkRTKey(PointerIsAssociatedWith)>(loc,
12572276bdaSValentin Clement                                                                      builder);
12672276bdaSValentin Clement   llvm::SmallVector<mlir::Value> args = fir::runtime::createArguments(
12772276bdaSValentin Clement       builder, loc, func.getType(), pointer, target);
12872276bdaSValentin Clement   return builder.create<fir::CallOp>(loc, func, args).getResult(0);
12972276bdaSValentin Clement }
130a1918fdfSValentin Clement 
1319daf5765SValentin Clement mlir::Value Fortran::lower::genCpuTime(fir::FirOpBuilder &builder,
1329daf5765SValentin Clement                                        mlir::Location loc) {
1339daf5765SValentin Clement   mlir::FuncOp func =
1349daf5765SValentin Clement       fir::runtime::getRuntimeFunc<mkRTKey(CpuTime)>(loc, builder);
1359daf5765SValentin Clement   return builder.create<fir::CallOp>(loc, func, llvm::None).getResult(0);
1369daf5765SValentin Clement }
1379daf5765SValentin Clement 
1389daf5765SValentin Clement void Fortran::lower::genDateAndTime(fir::FirOpBuilder &builder,
1399daf5765SValentin Clement                                     mlir::Location loc,
1409daf5765SValentin Clement                                     llvm::Optional<fir::CharBoxValue> date,
1419daf5765SValentin Clement                                     llvm::Optional<fir::CharBoxValue> time,
1429daf5765SValentin Clement                                     llvm::Optional<fir::CharBoxValue> zone,
1439daf5765SValentin Clement                                     mlir::Value values) {
1449daf5765SValentin Clement   mlir::FuncOp callee =
1459daf5765SValentin Clement       fir::runtime::getRuntimeFunc<mkRTKey(DateAndTime)>(loc, builder);
1469daf5765SValentin Clement   mlir::FunctionType funcTy = callee.getType();
1479daf5765SValentin Clement   mlir::Type idxTy = builder.getIndexType();
1489daf5765SValentin Clement   mlir::Value zero;
1499daf5765SValentin Clement   auto splitArg = [&](llvm::Optional<fir::CharBoxValue> arg,
1509daf5765SValentin Clement                       mlir::Value &buffer, mlir::Value &len) {
1519daf5765SValentin Clement     if (arg) {
1529daf5765SValentin Clement       buffer = arg->getBuffer();
1539daf5765SValentin Clement       len = arg->getLen();
1549daf5765SValentin Clement     } else {
1559daf5765SValentin Clement       if (!zero)
1569daf5765SValentin Clement         zero = builder.createIntegerConstant(loc, idxTy, 0);
1579daf5765SValentin Clement       buffer = zero;
1589daf5765SValentin Clement       len = zero;
1599daf5765SValentin Clement     }
1609daf5765SValentin Clement   };
1619daf5765SValentin Clement   mlir::Value dateBuffer;
1629daf5765SValentin Clement   mlir::Value dateLen;
1639daf5765SValentin Clement   splitArg(date, dateBuffer, dateLen);
1649daf5765SValentin Clement   mlir::Value timeBuffer;
1659daf5765SValentin Clement   mlir::Value timeLen;
1669daf5765SValentin Clement   splitArg(time, timeBuffer, timeLen);
1679daf5765SValentin Clement   mlir::Value zoneBuffer;
1689daf5765SValentin Clement   mlir::Value zoneLen;
1699daf5765SValentin Clement   splitArg(zone, zoneBuffer, zoneLen);
1709daf5765SValentin Clement 
1719daf5765SValentin Clement   mlir::Value sourceFile = fir::factory::locationToFilename(builder, loc);
1729daf5765SValentin Clement   mlir::Value sourceLine =
1739daf5765SValentin Clement       fir::factory::locationToLineNo(builder, loc, funcTy.getInput(7));
1749daf5765SValentin Clement 
1759daf5765SValentin Clement   llvm::SmallVector<mlir::Value> args = fir::runtime::createArguments(
1769daf5765SValentin Clement       builder, loc, funcTy, dateBuffer, dateLen, timeBuffer, timeLen,
1779daf5765SValentin Clement       zoneBuffer, zoneLen, sourceFile, sourceLine, values);
1789daf5765SValentin Clement   builder.create<fir::CallOp>(loc, callee, args);
1799daf5765SValentin Clement }
1809daf5765SValentin Clement 
181a1918fdfSValentin Clement void Fortran::lower::genRandomInit(fir::FirOpBuilder &builder,
182a1918fdfSValentin Clement                                    mlir::Location loc, mlir::Value repeatable,
183a1918fdfSValentin Clement                                    mlir::Value imageDistinct) {
184a1918fdfSValentin Clement   mlir::FuncOp func =
185a1918fdfSValentin Clement       fir::runtime::getRuntimeFunc<mkRTKey(RandomInit)>(loc, builder);
186a1918fdfSValentin Clement   llvm::SmallVector<mlir::Value> args = fir::runtime::createArguments(
187a1918fdfSValentin Clement       builder, loc, func.getType(), repeatable, imageDistinct);
188a1918fdfSValentin Clement   builder.create<fir::CallOp>(loc, func, args);
189a1918fdfSValentin Clement }
190a1918fdfSValentin Clement 
191a1918fdfSValentin Clement void Fortran::lower::genRandomNumber(fir::FirOpBuilder &builder,
192a1918fdfSValentin Clement                                      mlir::Location loc, mlir::Value harvest) {
193a1918fdfSValentin Clement   mlir::FuncOp func =
194a1918fdfSValentin Clement       fir::runtime::getRuntimeFunc<mkRTKey(RandomNumber)>(loc, builder);
195a1918fdfSValentin Clement   mlir::FunctionType funcTy = func.getType();
196a1918fdfSValentin Clement   mlir::Value sourceFile = fir::factory::locationToFilename(builder, loc);
197a1918fdfSValentin Clement   mlir::Value sourceLine =
198a1918fdfSValentin Clement       fir::factory::locationToLineNo(builder, loc, funcTy.getInput(2));
199a1918fdfSValentin Clement   llvm::SmallVector<mlir::Value> args = fir::runtime::createArguments(
200a1918fdfSValentin Clement       builder, loc, funcTy, harvest, sourceFile, sourceLine);
201a1918fdfSValentin Clement   builder.create<fir::CallOp>(loc, func, args);
202a1918fdfSValentin Clement }
203a1918fdfSValentin Clement 
204a1918fdfSValentin Clement void Fortran::lower::genRandomSeed(fir::FirOpBuilder &builder,
205a1918fdfSValentin Clement                                    mlir::Location loc, int argIndex,
206a1918fdfSValentin Clement                                    mlir::Value argBox) {
207a1918fdfSValentin Clement   mlir::FuncOp func;
208a1918fdfSValentin Clement   // argIndex is the nth (0-origin) argument in declaration order,
209a1918fdfSValentin Clement   // or -1 if no argument is present.
210a1918fdfSValentin Clement   switch (argIndex) {
211a1918fdfSValentin Clement   case -1:
212a1918fdfSValentin Clement     func = fir::runtime::getRuntimeFunc<mkRTKey(RandomSeedDefaultPut)>(loc,
213a1918fdfSValentin Clement                                                                        builder);
214a1918fdfSValentin Clement     builder.create<fir::CallOp>(loc, func);
215a1918fdfSValentin Clement     return;
216a1918fdfSValentin Clement   case 0:
217a1918fdfSValentin Clement     func = fir::runtime::getRuntimeFunc<mkRTKey(RandomSeedSize)>(loc, builder);
218a1918fdfSValentin Clement     break;
219a1918fdfSValentin Clement   case 1:
220a1918fdfSValentin Clement     func = fir::runtime::getRuntimeFunc<mkRTKey(RandomSeedPut)>(loc, builder);
221a1918fdfSValentin Clement     break;
222a1918fdfSValentin Clement   case 2:
223a1918fdfSValentin Clement     func = fir::runtime::getRuntimeFunc<mkRTKey(RandomSeedGet)>(loc, builder);
224a1918fdfSValentin Clement     break;
225a1918fdfSValentin Clement   default:
226a1918fdfSValentin Clement     llvm::report_fatal_error("invalid RANDOM_SEED argument index");
227a1918fdfSValentin Clement   }
228a1918fdfSValentin Clement   mlir::FunctionType funcTy = func.getType();
229a1918fdfSValentin Clement   mlir::Value sourceFile = fir::factory::locationToFilename(builder, loc);
230a1918fdfSValentin Clement   mlir::Value sourceLine =
231a1918fdfSValentin Clement       fir::factory::locationToLineNo(builder, loc, funcTy.getInput(2));
232a1918fdfSValentin Clement   llvm::SmallVector<mlir::Value> args = fir::runtime::createArguments(
233a1918fdfSValentin Clement       builder, loc, funcTy, argBox, sourceFile, sourceLine);
234a1918fdfSValentin Clement   builder.create<fir::CallOp>(loc, func, args);
235a1918fdfSValentin Clement }
236*264d9662SValentin Clement 
237*264d9662SValentin Clement /// generate system_clock runtime call/s
238*264d9662SValentin Clement /// all intrinsic arguments are optional and may appear here as mlir::Value{}
239*264d9662SValentin Clement void Fortran::lower::genSystemClock(fir::FirOpBuilder &builder,
240*264d9662SValentin Clement                                     mlir::Location loc, mlir::Value count,
241*264d9662SValentin Clement                                     mlir::Value rate, mlir::Value max) {
242*264d9662SValentin Clement   auto makeCall = [&](mlir::FuncOp func, mlir::Value arg) {
243*264d9662SValentin Clement     mlir::Type kindTy = func.getType().getInput(0);
244*264d9662SValentin Clement     int integerKind = 8;
245*264d9662SValentin Clement     if (auto intType =
246*264d9662SValentin Clement             fir::unwrapRefType(arg.getType()).dyn_cast<mlir::IntegerType>())
247*264d9662SValentin Clement       integerKind = intType.getWidth() / 8;
248*264d9662SValentin Clement     mlir::Value kind = builder.createIntegerConstant(loc, kindTy, integerKind);
249*264d9662SValentin Clement     mlir::Value res =
250*264d9662SValentin Clement         builder.create<fir::CallOp>(loc, func, mlir::ValueRange{kind})
251*264d9662SValentin Clement             .getResult(0);
252*264d9662SValentin Clement     mlir::Value castRes =
253*264d9662SValentin Clement         builder.createConvert(loc, fir::dyn_cast_ptrEleTy(arg.getType()), res);
254*264d9662SValentin Clement     builder.create<fir::StoreOp>(loc, castRes, arg);
255*264d9662SValentin Clement   };
256*264d9662SValentin Clement   using fir::runtime::getRuntimeFunc;
257*264d9662SValentin Clement   if (count)
258*264d9662SValentin Clement     makeCall(getRuntimeFunc<mkRTKey(SystemClockCount)>(loc, builder), count);
259*264d9662SValentin Clement   if (rate)
260*264d9662SValentin Clement     makeCall(getRuntimeFunc<mkRTKey(SystemClockCountRate)>(loc, builder), rate);
261*264d9662SValentin Clement   if (max)
262*264d9662SValentin Clement     makeCall(getRuntimeFunc<mkRTKey(SystemClockCountMax)>(loc, builder), max);
263*264d9662SValentin Clement }
264