1 //===-- Runtime.cpp -------------------------------------------------------===// 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 #include "flang/Lower/Runtime.h" 10 #include "flang/Lower/Bridge.h" 11 #include "flang/Lower/StatementContext.h" 12 #include "flang/Lower/Todo.h" 13 #include "flang/Optimizer/Builder/FIRBuilder.h" 14 #include "flang/Optimizer/Builder/Runtime/RTBuilder.h" 15 #include "flang/Parser/parse-tree.h" 16 #include "flang/Runtime/pointer.h" 17 #include "flang/Runtime/stop.h" 18 #include "flang/Semantics/tools.h" 19 #include "llvm/Support/Debug.h" 20 21 #define DEBUG_TYPE "flang-lower-runtime" 22 23 using namespace Fortran::runtime; 24 25 /// Runtime calls that do not return to the caller indicate this condition by 26 /// terminating the current basic block with an unreachable op. 27 static void genUnreachable(fir::FirOpBuilder &builder, mlir::Location loc) { 28 builder.create<fir::UnreachableOp>(loc); 29 mlir::Block *newBlock = 30 builder.getBlock()->splitBlock(builder.getInsertionPoint()); 31 builder.setInsertionPointToStart(newBlock); 32 } 33 34 //===----------------------------------------------------------------------===// 35 // Misc. Fortran statements that lower to runtime calls 36 //===----------------------------------------------------------------------===// 37 38 void Fortran::lower::genStopStatement( 39 Fortran::lower::AbstractConverter &converter, 40 const Fortran::parser::StopStmt &stmt) { 41 fir::FirOpBuilder &builder = converter.getFirOpBuilder(); 42 mlir::Location loc = converter.getCurrentLocation(); 43 Fortran::lower::StatementContext stmtCtx; 44 llvm::SmallVector<mlir::Value> operands; 45 mlir::FuncOp callee; 46 mlir::FunctionType calleeType; 47 // First operand is stop code (zero if absent) 48 if (const auto &code = 49 std::get<std::optional<Fortran::parser::StopCode>>(stmt.t)) { 50 auto expr = 51 converter.genExprValue(*Fortran::semantics::GetExpr(*code), stmtCtx); 52 LLVM_DEBUG(llvm::dbgs() << "stop expression: "; expr.dump(); 53 llvm::dbgs() << '\n'); 54 expr.match( 55 [&](const fir::CharBoxValue &x) { 56 callee = fir::runtime::getRuntimeFunc<mkRTKey(StopStatementText)>( 57 loc, builder); 58 calleeType = callee.getType(); 59 // Creates a pair of operands for the CHARACTER and its LEN. 60 operands.push_back( 61 builder.createConvert(loc, calleeType.getInput(0), x.getAddr())); 62 operands.push_back( 63 builder.createConvert(loc, calleeType.getInput(1), x.getLen())); 64 }, 65 [&](fir::UnboxedValue x) { 66 callee = fir::runtime::getRuntimeFunc<mkRTKey(StopStatement)>( 67 loc, builder); 68 calleeType = callee.getType(); 69 mlir::Value cast = 70 builder.createConvert(loc, calleeType.getInput(0), x); 71 operands.push_back(cast); 72 }, 73 [&](auto) { 74 mlir::emitError(loc, "unhandled expression in STOP"); 75 std::exit(1); 76 }); 77 } else { 78 callee = fir::runtime::getRuntimeFunc<mkRTKey(StopStatement)>(loc, builder); 79 calleeType = callee.getType(); 80 operands.push_back( 81 builder.createIntegerConstant(loc, calleeType.getInput(0), 0)); 82 } 83 84 // Second operand indicates ERROR STOP 85 bool isError = std::get<Fortran::parser::StopStmt::Kind>(stmt.t) == 86 Fortran::parser::StopStmt::Kind::ErrorStop; 87 operands.push_back(builder.createIntegerConstant( 88 loc, calleeType.getInput(operands.size()), isError)); 89 90 // Third operand indicates QUIET (default to false). 91 if (const auto &quiet = 92 std::get<std::optional<Fortran::parser::ScalarLogicalExpr>>(stmt.t)) { 93 const SomeExpr *expr = Fortran::semantics::GetExpr(*quiet); 94 assert(expr && "failed getting typed expression"); 95 mlir::Value q = fir::getBase(converter.genExprValue(*expr, stmtCtx)); 96 operands.push_back( 97 builder.createConvert(loc, calleeType.getInput(operands.size()), q)); 98 } else { 99 operands.push_back(builder.createIntegerConstant( 100 loc, calleeType.getInput(operands.size()), 0)); 101 } 102 103 builder.create<fir::CallOp>(loc, callee, operands); 104 genUnreachable(builder, loc); 105 } 106 107 void Fortran::lower::genPauseStatement( 108 Fortran::lower::AbstractConverter &converter, 109 const Fortran::parser::PauseStmt &) { 110 fir::FirOpBuilder &builder = converter.getFirOpBuilder(); 111 mlir::Location loc = converter.getCurrentLocation(); 112 mlir::FuncOp callee = 113 fir::runtime::getRuntimeFunc<mkRTKey(PauseStatement)>(loc, builder); 114 builder.create<fir::CallOp>(loc, callee, llvm::None); 115 } 116 117 mlir::Value Fortran::lower::genAssociated(fir::FirOpBuilder &builder, 118 mlir::Location loc, 119 mlir::Value pointer, 120 mlir::Value target) { 121 mlir::FuncOp func = 122 fir::runtime::getRuntimeFunc<mkRTKey(PointerIsAssociatedWith)>(loc, 123 builder); 124 llvm::SmallVector<mlir::Value> args = fir::runtime::createArguments( 125 builder, loc, func.getType(), pointer, target); 126 return builder.create<fir::CallOp>(loc, func, args).getResult(0); 127 } 128