| 1 | //===- GenRuntimeCallsForTest.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 | //===----------------------------------------------------------------------===// |
| 10 | /// \file |
| 11 | /// This pass is only for developers to generate declarations/calls |
| 12 | /// of Fortran runtime function recognized in |
| 13 | /// flang/Optimizer/Transforms/RuntimeFunctions.inc table. |
| 14 | /// Sample of the generated FIR: |
| 15 | /// func.func private |
| 16 | /// @_FortranAioSetStatus(!fir.ref<i8>, !fir.ref<i8>, i64) -> |
| 17 | /// i1 attributes {fir.io, fir.runtime} |
| 18 | /// |
| 19 | /// func.func @test__FortranAioSetStatus( |
| 20 | /// %arg0: !fir.ref<i8>, %arg1: !fir.ref<i8>, %arg2: i64) -> i1 { |
| 21 | /// %0 = fir.call @_FortranAioSetStatus(%arg0, %arg1, %arg2) : |
| 22 | /// (!fir.ref<i8>, !fir.ref<i8>, i64) -> i1 |
| 23 | /// return %0 : i1 |
| 24 | /// } |
| 25 | //===----------------------------------------------------------------------===// |
| 26 | #include "flang/Common/static-multimap-view.h" |
| 27 | #include "flang/Optimizer/Builder/Runtime/RTBuilder.h" |
| 28 | #include "flang/Optimizer/Dialect/FIRDialect.h" |
| 29 | #include "flang/Optimizer/Dialect/FIROpsSupport.h" |
| 30 | #include "flang/Optimizer/Support/InternalNames.h" |
| 31 | #include "flang/Optimizer/Transforms/Passes.h" |
| 32 | #include "flang/Runtime/io-api.h" |
| 33 | #include "mlir/Dialect/LLVMIR/LLVMAttrs.h" |
| 34 | |
| 35 | namespace fir { |
| 36 | #define GEN_PASS_DEF_GENRUNTIMECALLSFORTEST |
| 37 | #include "flang/Optimizer/Transforms/Passes.h.inc" |
| 38 | } // namespace fir |
| 39 | |
| 40 | #define DEBUG_TYPE "gen-runtime-calls-for-test" |
| 41 | |
| 42 | using namespace Fortran::runtime; |
| 43 | using namespace Fortran::runtime::io; |
| 44 | |
| 45 | #define mkIOKey(X) FirmkKey(IONAME(X)) |
| 46 | #define mkRTKey(X) FirmkKey(RTNAME(X)) |
| 47 | |
| 48 | namespace { |
| 49 | class GenRuntimeCallsForTestPass |
| 50 | : public fir::impl::GenRuntimeCallsForTestBase<GenRuntimeCallsForTestPass> { |
| 51 | using GenRuntimeCallsForTestBase< |
| 52 | GenRuntimeCallsForTestPass>::GenRuntimeCallsForTestBase; |
| 53 | |
| 54 | public: |
| 55 | void runOnOperation() override; |
| 56 | }; |
| 57 | } // end anonymous namespace |
| 58 | |
| 59 | static constexpr llvm::StringRef testPrefix = "test_" ; |
| 60 | |
| 61 | void GenRuntimeCallsForTestPass::runOnOperation() { |
| 62 | mlir::ModuleOp moduleOp = getOperation(); |
| 63 | mlir::OpBuilder mlirBuilder(moduleOp.getRegion()); |
| 64 | fir::FirOpBuilder builder(mlirBuilder, moduleOp); |
| 65 | mlir::Location loc = mlir::UnknownLoc::get(builder.getContext()); |
| 66 | |
| 67 | #define KNOWN_IO_FUNC(X) \ |
| 68 | fir::runtime::getIORuntimeFunc<mkIOKey(X)>(loc, builder) |
| 69 | #define KNOWN_RUNTIME_FUNC(X) \ |
| 70 | fir::runtime::getRuntimeFunc<mkRTKey(X)>(loc, builder) |
| 71 | |
| 72 | mlir::func::FuncOp runtimeFuncsTable[] = { |
| 73 | #include "flang/Optimizer/Transforms/RuntimeFunctions.inc" |
| 74 | }; |
| 75 | |
| 76 | if (!doGenerateCalls) |
| 77 | return; |
| 78 | |
| 79 | // Generate thin wrapper functions calling the known Fortran |
| 80 | // runtime functions. |
| 81 | llvm::SmallVector<mlir::Operation *> newFuncs; |
| 82 | for (unsigned i = 0; |
| 83 | i < sizeof(runtimeFuncsTable) / sizeof(runtimeFuncsTable[0]); ++i) { |
| 84 | mlir::func::FuncOp funcOp = runtimeFuncsTable[i]; |
| 85 | mlir::FunctionType funcTy = funcOp.getFunctionType(); |
| 86 | std::string name = (llvm::Twine(testPrefix) + funcOp.getName()).str(); |
| 87 | mlir::func::FuncOp callerFunc = builder.createFunction(loc, name, funcTy); |
| 88 | callerFunc.setVisibility(mlir::SymbolTable::Visibility::Public); |
| 89 | mlir::OpBuilder::InsertPoint insertPt = builder.saveInsertionPoint(); |
| 90 | |
| 91 | // Generate the wrapper function body that consists of a call and return. |
| 92 | builder.setInsertionPointToStart(callerFunc.addEntryBlock()); |
| 93 | mlir::Block::BlockArgListType args = callerFunc.front().getArguments(); |
| 94 | auto callOp = builder.create<fir::CallOp>(loc, funcOp, args); |
| 95 | builder.create<mlir::func::ReturnOp>(loc, callOp.getResults()); |
| 96 | |
| 97 | newFuncs.push_back(callerFunc.getOperation()); |
| 98 | builder.restoreInsertionPoint(insertPt); |
| 99 | } |
| 100 | |
| 101 | // Make sure all wrapper functions are at the beginning |
| 102 | // of the module. |
| 103 | auto moduleBegin = moduleOp.getBody()->begin(); |
| 104 | for (auto func : newFuncs) |
| 105 | func->moveBefore(moduleOp.getBody(), moduleBegin); |
| 106 | } |
| 107 | |