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