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 | |