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" 17*a1918fdfSValentin Clement #include "flang/Runtime/random.h" 18aab4263aSValentin Clement #include "flang/Runtime/stop.h" 19aab4263aSValentin Clement #include "flang/Semantics/tools.h" 20aab4263aSValentin Clement #include "llvm/Support/Debug.h" 21aab4263aSValentin Clement 22aab4263aSValentin Clement #define DEBUG_TYPE "flang-lower-runtime" 23aab4263aSValentin Clement 24aab4263aSValentin Clement using namespace Fortran::runtime; 25aab4263aSValentin Clement 26aab4263aSValentin Clement /// Runtime calls that do not return to the caller indicate this condition by 27aab4263aSValentin Clement /// terminating the current basic block with an unreachable op. 28aab4263aSValentin Clement static void genUnreachable(fir::FirOpBuilder &builder, mlir::Location loc) { 29aab4263aSValentin Clement builder.create<fir::UnreachableOp>(loc); 30aab4263aSValentin Clement mlir::Block *newBlock = 31aab4263aSValentin Clement builder.getBlock()->splitBlock(builder.getInsertionPoint()); 32aab4263aSValentin Clement builder.setInsertionPointToStart(newBlock); 33aab4263aSValentin Clement } 34aab4263aSValentin Clement 35aab4263aSValentin Clement //===----------------------------------------------------------------------===// 36aab4263aSValentin Clement // Misc. Fortran statements that lower to runtime calls 37aab4263aSValentin Clement //===----------------------------------------------------------------------===// 38aab4263aSValentin Clement 39aab4263aSValentin Clement void Fortran::lower::genStopStatement( 40aab4263aSValentin Clement Fortran::lower::AbstractConverter &converter, 41aab4263aSValentin Clement const Fortran::parser::StopStmt &stmt) { 42aab4263aSValentin Clement fir::FirOpBuilder &builder = converter.getFirOpBuilder(); 43aab4263aSValentin Clement mlir::Location loc = converter.getCurrentLocation(); 44d0b70a07SValentin Clement Fortran::lower::StatementContext stmtCtx; 45aab4263aSValentin Clement llvm::SmallVector<mlir::Value> operands; 46aab4263aSValentin Clement mlir::FuncOp callee; 47aab4263aSValentin Clement mlir::FunctionType calleeType; 48aab4263aSValentin Clement // First operand is stop code (zero if absent) 49ca53e049SValentin Clement if (const auto &code = 50ca53e049SValentin Clement std::get<std::optional<Fortran::parser::StopCode>>(stmt.t)) { 51d0b70a07SValentin Clement auto expr = 52d0b70a07SValentin Clement converter.genExprValue(*Fortran::semantics::GetExpr(*code), stmtCtx); 53ca53e049SValentin Clement LLVM_DEBUG(llvm::dbgs() << "stop expression: "; expr.dump(); 54ca53e049SValentin Clement llvm::dbgs() << '\n'); 55ca53e049SValentin Clement expr.match( 56ca53e049SValentin Clement [&](const fir::CharBoxValue &x) { 57a8d48fe0SValentin Clement callee = fir::runtime::getRuntimeFunc<mkRTKey(StopStatementText)>( 58a8d48fe0SValentin Clement loc, builder); 59a8d48fe0SValentin Clement calleeType = callee.getType(); 60a8d48fe0SValentin Clement // Creates a pair of operands for the CHARACTER and its LEN. 61a8d48fe0SValentin Clement operands.push_back( 62a8d48fe0SValentin Clement builder.createConvert(loc, calleeType.getInput(0), x.getAddr())); 63a8d48fe0SValentin Clement operands.push_back( 64a8d48fe0SValentin Clement builder.createConvert(loc, calleeType.getInput(1), x.getLen())); 65ca53e049SValentin Clement }, 66ca53e049SValentin Clement [&](fir::UnboxedValue x) { 67ca53e049SValentin Clement callee = fir::runtime::getRuntimeFunc<mkRTKey(StopStatement)>( 68ca53e049SValentin Clement loc, builder); 69ca53e049SValentin Clement calleeType = callee.getType(); 70ca53e049SValentin Clement mlir::Value cast = 71ca53e049SValentin Clement builder.createConvert(loc, calleeType.getInput(0), x); 72ca53e049SValentin Clement operands.push_back(cast); 73ca53e049SValentin Clement }, 74ca53e049SValentin Clement [&](auto) { 75ca53e049SValentin Clement mlir::emitError(loc, "unhandled expression in STOP"); 76ca53e049SValentin Clement std::exit(1); 77ca53e049SValentin Clement }); 78aab4263aSValentin Clement } else { 79aab4263aSValentin Clement callee = fir::runtime::getRuntimeFunc<mkRTKey(StopStatement)>(loc, builder); 80aab4263aSValentin Clement calleeType = callee.getType(); 81aab4263aSValentin Clement operands.push_back( 82aab4263aSValentin Clement builder.createIntegerConstant(loc, calleeType.getInput(0), 0)); 83aab4263aSValentin Clement } 84aab4263aSValentin Clement 85aab4263aSValentin Clement // Second operand indicates ERROR STOP 86aab4263aSValentin Clement bool isError = std::get<Fortran::parser::StopStmt::Kind>(stmt.t) == 87aab4263aSValentin Clement Fortran::parser::StopStmt::Kind::ErrorStop; 88aab4263aSValentin Clement operands.push_back(builder.createIntegerConstant( 89aab4263aSValentin Clement loc, calleeType.getInput(operands.size()), isError)); 90aab4263aSValentin Clement 91aab4263aSValentin Clement // Third operand indicates QUIET (default to false). 92cc306740SValentin Clement if (const auto &quiet = 93cc306740SValentin Clement std::get<std::optional<Fortran::parser::ScalarLogicalExpr>>(stmt.t)) { 94cc306740SValentin Clement const SomeExpr *expr = Fortran::semantics::GetExpr(*quiet); 95cc306740SValentin Clement assert(expr && "failed getting typed expression"); 96d0b70a07SValentin Clement mlir::Value q = fir::getBase(converter.genExprValue(*expr, stmtCtx)); 97cc306740SValentin Clement operands.push_back( 98cc306740SValentin Clement builder.createConvert(loc, calleeType.getInput(operands.size()), q)); 99aab4263aSValentin Clement } else { 100aab4263aSValentin Clement operands.push_back(builder.createIntegerConstant( 101aab4263aSValentin Clement loc, calleeType.getInput(operands.size()), 0)); 102aab4263aSValentin Clement } 103aab4263aSValentin Clement 104aab4263aSValentin Clement builder.create<fir::CallOp>(loc, callee, operands); 105aab4263aSValentin Clement genUnreachable(builder, loc); 106aab4263aSValentin Clement } 107db01b123SValentin Clement 108db01b123SValentin Clement void Fortran::lower::genPauseStatement( 109db01b123SValentin Clement Fortran::lower::AbstractConverter &converter, 110db01b123SValentin Clement const Fortran::parser::PauseStmt &) { 111db01b123SValentin Clement fir::FirOpBuilder &builder = converter.getFirOpBuilder(); 112db01b123SValentin Clement mlir::Location loc = converter.getCurrentLocation(); 113db01b123SValentin Clement mlir::FuncOp callee = 114db01b123SValentin Clement fir::runtime::getRuntimeFunc<mkRTKey(PauseStatement)>(loc, builder); 115db01b123SValentin Clement builder.create<fir::CallOp>(loc, callee, llvm::None); 116db01b123SValentin Clement } 11772276bdaSValentin Clement 11872276bdaSValentin Clement mlir::Value Fortran::lower::genAssociated(fir::FirOpBuilder &builder, 11972276bdaSValentin Clement mlir::Location loc, 12072276bdaSValentin Clement mlir::Value pointer, 12172276bdaSValentin Clement mlir::Value target) { 12272276bdaSValentin Clement mlir::FuncOp func = 12372276bdaSValentin Clement fir::runtime::getRuntimeFunc<mkRTKey(PointerIsAssociatedWith)>(loc, 12472276bdaSValentin Clement builder); 12572276bdaSValentin Clement llvm::SmallVector<mlir::Value> args = fir::runtime::createArguments( 12672276bdaSValentin Clement builder, loc, func.getType(), pointer, target); 12772276bdaSValentin Clement return builder.create<fir::CallOp>(loc, func, args).getResult(0); 12872276bdaSValentin Clement } 129*a1918fdfSValentin Clement 130*a1918fdfSValentin Clement void Fortran::lower::genRandomInit(fir::FirOpBuilder &builder, 131*a1918fdfSValentin Clement mlir::Location loc, mlir::Value repeatable, 132*a1918fdfSValentin Clement mlir::Value imageDistinct) { 133*a1918fdfSValentin Clement mlir::FuncOp func = 134*a1918fdfSValentin Clement fir::runtime::getRuntimeFunc<mkRTKey(RandomInit)>(loc, builder); 135*a1918fdfSValentin Clement llvm::SmallVector<mlir::Value> args = fir::runtime::createArguments( 136*a1918fdfSValentin Clement builder, loc, func.getType(), repeatable, imageDistinct); 137*a1918fdfSValentin Clement builder.create<fir::CallOp>(loc, func, args); 138*a1918fdfSValentin Clement } 139*a1918fdfSValentin Clement 140*a1918fdfSValentin Clement void Fortran::lower::genRandomNumber(fir::FirOpBuilder &builder, 141*a1918fdfSValentin Clement mlir::Location loc, mlir::Value harvest) { 142*a1918fdfSValentin Clement mlir::FuncOp func = 143*a1918fdfSValentin Clement fir::runtime::getRuntimeFunc<mkRTKey(RandomNumber)>(loc, builder); 144*a1918fdfSValentin Clement mlir::FunctionType funcTy = func.getType(); 145*a1918fdfSValentin Clement mlir::Value sourceFile = fir::factory::locationToFilename(builder, loc); 146*a1918fdfSValentin Clement mlir::Value sourceLine = 147*a1918fdfSValentin Clement fir::factory::locationToLineNo(builder, loc, funcTy.getInput(2)); 148*a1918fdfSValentin Clement llvm::SmallVector<mlir::Value> args = fir::runtime::createArguments( 149*a1918fdfSValentin Clement builder, loc, funcTy, harvest, sourceFile, sourceLine); 150*a1918fdfSValentin Clement builder.create<fir::CallOp>(loc, func, args); 151*a1918fdfSValentin Clement } 152*a1918fdfSValentin Clement 153*a1918fdfSValentin Clement void Fortran::lower::genRandomSeed(fir::FirOpBuilder &builder, 154*a1918fdfSValentin Clement mlir::Location loc, int argIndex, 155*a1918fdfSValentin Clement mlir::Value argBox) { 156*a1918fdfSValentin Clement mlir::FuncOp func; 157*a1918fdfSValentin Clement // argIndex is the nth (0-origin) argument in declaration order, 158*a1918fdfSValentin Clement // or -1 if no argument is present. 159*a1918fdfSValentin Clement switch (argIndex) { 160*a1918fdfSValentin Clement case -1: 161*a1918fdfSValentin Clement func = fir::runtime::getRuntimeFunc<mkRTKey(RandomSeedDefaultPut)>(loc, 162*a1918fdfSValentin Clement builder); 163*a1918fdfSValentin Clement builder.create<fir::CallOp>(loc, func); 164*a1918fdfSValentin Clement return; 165*a1918fdfSValentin Clement case 0: 166*a1918fdfSValentin Clement func = fir::runtime::getRuntimeFunc<mkRTKey(RandomSeedSize)>(loc, builder); 167*a1918fdfSValentin Clement break; 168*a1918fdfSValentin Clement case 1: 169*a1918fdfSValentin Clement func = fir::runtime::getRuntimeFunc<mkRTKey(RandomSeedPut)>(loc, builder); 170*a1918fdfSValentin Clement break; 171*a1918fdfSValentin Clement case 2: 172*a1918fdfSValentin Clement func = fir::runtime::getRuntimeFunc<mkRTKey(RandomSeedGet)>(loc, builder); 173*a1918fdfSValentin Clement break; 174*a1918fdfSValentin Clement default: 175*a1918fdfSValentin Clement llvm::report_fatal_error("invalid RANDOM_SEED argument index"); 176*a1918fdfSValentin Clement } 177*a1918fdfSValentin Clement mlir::FunctionType funcTy = func.getType(); 178*a1918fdfSValentin Clement mlir::Value sourceFile = fir::factory::locationToFilename(builder, loc); 179*a1918fdfSValentin Clement mlir::Value sourceLine = 180*a1918fdfSValentin Clement fir::factory::locationToLineNo(builder, loc, funcTy.getInput(2)); 181*a1918fdfSValentin Clement llvm::SmallVector<mlir::Value> args = fir::runtime::createArguments( 182*a1918fdfSValentin Clement builder, loc, funcTy, argBox, sourceFile, sourceLine); 183*a1918fdfSValentin Clement builder.create<fir::CallOp>(loc, func, args); 184*a1918fdfSValentin Clement } 185