|
| 1 | +//===-- Lower/CallInterface.h -- Procedure call interface ------*- C++ -*-===// |
| 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 | +// Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/ |
| 10 | +// |
| 11 | +//===----------------------------------------------------------------------===// |
| 12 | +// |
| 13 | +// Utility that defines fir call interface for procedure both on caller and |
| 14 | +// and callee side and get the related FuncOp. |
| 15 | +// It does not emit any FIR code but for the created mlir::FuncOp, instead it |
| 16 | +// provides back a container of Symbol (callee side)/ActualArgument (caller |
| 17 | +// side) with additional information for each element describing how it must be |
| 18 | +// plugged with the mlir::FuncOp. |
| 19 | +// It handles the fact that hidden arguments may be inserted for the result. |
| 20 | +// while lowering. |
| 21 | +// |
| 22 | +// This utility uses the characteristic of Fortran procedures to operate, which |
| 23 | +// is a term and concept used in Fortran to refer to the signature of a function |
| 24 | +// or subroutine. |
| 25 | +//===----------------------------------------------------------------------===// |
| 26 | + |
| 27 | +#ifndef FORTRAN_LOWER_CALLINTERFACE_H |
| 28 | +#define FORTRAN_LOWER_CALLINTERFACE_H |
| 29 | + |
| 30 | +#include "flang/Common/reference.h" |
| 31 | +#include "flang/Evaluate/characteristics.h" |
| 32 | +#include "mlir/IR/BuiltinOps.h" |
| 33 | +#include <memory> |
| 34 | +#include <optional> |
| 35 | + |
| 36 | +namespace Fortran::semantics { |
| 37 | +class Symbol; |
| 38 | +} |
| 39 | + |
| 40 | +namespace mlir { |
| 41 | +class Location; |
| 42 | +} |
| 43 | + |
| 44 | +namespace Fortran::lower { |
| 45 | +class AbstractConverter; |
| 46 | +namespace pft { |
| 47 | +struct FunctionLikeUnit; |
| 48 | +} |
| 49 | + |
| 50 | +/// PassedEntityTypes helps abstract whether CallInterface is mapping a |
| 51 | +/// Symbol to mlir::Value (callee side) or an ActualArgument to a position |
| 52 | +/// inside the input vector for the CallOp (caller side. It will be up to the |
| 53 | +/// CallInterface user to produce the mlir::Value that will go in this input |
| 54 | +/// vector). |
| 55 | +class CalleeInterface; |
| 56 | +template <typename T> |
| 57 | +struct PassedEntityTypes {}; |
| 58 | +template <> |
| 59 | +struct PassedEntityTypes<CalleeInterface> { |
| 60 | + using FortranEntity = |
| 61 | + std::optional<common::Reference<const semantics::Symbol>>; |
| 62 | + using FirValue = mlir::Value; |
| 63 | +}; |
| 64 | + |
| 65 | +/// Implementation helper |
| 66 | +template <typename T> |
| 67 | +class CallInterfaceImpl; |
| 68 | + |
| 69 | +/// CallInterface defines all the logic to determine FIR function interfaces |
| 70 | +/// from a characteristic, build the mlir::FuncOp and describe back the argument |
| 71 | +/// mapping to its user. |
| 72 | +/// The logic is shared between the callee and caller sides that it accepts as |
| 73 | +/// a curiously recursive template to handle the few things that cannot be |
| 74 | +/// shared between both sides (getting characteristics, mangled name, location). |
| 75 | +/// It maps FIR arguments to front-end Symbol (callee side) or ActualArgument |
| 76 | +/// (caller side) with the same code using the abstract FortranEntity type that |
| 77 | +/// can be either a Symbol or an ActualArgument. |
| 78 | +/// It works in two passes: a first pass over the characteristics that decides |
| 79 | +/// how the interface must be. Then, the funcOp is created for it. Then a simple |
| 80 | +/// pass over fir arguments finalizes the interface information that must be |
| 81 | +/// passed back to the user (and may require having the funcOp). All these |
| 82 | +/// passes are driven from the CallInterface constructor. |
| 83 | +template <typename T> |
| 84 | +class CallInterface { |
| 85 | + friend CallInterfaceImpl<T>; |
| 86 | + |
| 87 | +public: |
| 88 | + /// Different properties of an entity that can be passed/returned. |
| 89 | + /// One-to-One mapping with PassEntityBy but for |
| 90 | + /// PassEntityBy::AddressAndLength that has two properties. |
| 91 | + enum class Property { |
| 92 | + BaseAddress, |
| 93 | + BoxChar, |
| 94 | + CharAddress, |
| 95 | + CharLength, |
| 96 | + CharProcTuple, |
| 97 | + Box, |
| 98 | + MutableBox, |
| 99 | + Value |
| 100 | + }; |
| 101 | + |
| 102 | + using FortranEntity = typename PassedEntityTypes<T>::FortranEntity; |
| 103 | + using FirValue = typename PassedEntityTypes<T>::FirValue; |
| 104 | + |
| 105 | + /// Returns the mlir function type |
| 106 | + mlir::FunctionType genFunctionType(); |
| 107 | + |
| 108 | +protected: |
| 109 | + CallInterface(Fortran::lower::AbstractConverter &c) : converter{c} {} |
| 110 | + /// CRTP handle. |
| 111 | + T &side() { return *static_cast<T *>(this); } |
| 112 | + /// Entry point to be called by child ctor to analyze the signature and |
| 113 | + /// create/find the mlir::FuncOp. Child needs to be initialized first. |
| 114 | + void declare(); |
| 115 | + |
| 116 | + mlir::FuncOp func; |
| 117 | + |
| 118 | + Fortran::lower::AbstractConverter &converter; |
| 119 | +}; |
| 120 | + |
| 121 | +//===----------------------------------------------------------------------===// |
| 122 | +// Callee side interface |
| 123 | +//===----------------------------------------------------------------------===// |
| 124 | + |
| 125 | +/// CalleeInterface only provides the helpers needed by CallInterface |
| 126 | +/// to abstract the specificities of the callee side. |
| 127 | +class CalleeInterface : public CallInterface<CalleeInterface> { |
| 128 | +public: |
| 129 | + CalleeInterface(Fortran::lower::pft::FunctionLikeUnit &f, |
| 130 | + Fortran::lower::AbstractConverter &c) |
| 131 | + : CallInterface{c}, funit{f} { |
| 132 | + declare(); |
| 133 | + } |
| 134 | + |
| 135 | + std::string getMangledName() const; |
| 136 | + mlir::Location getCalleeLocation() const; |
| 137 | + Fortran::evaluate::characteristics::Procedure characterize() const; |
| 138 | + |
| 139 | + /// On the callee side it does not matter whether the procedure is |
| 140 | + /// called through pointers or not. |
| 141 | + bool isIndirectCall() const { return false; } |
| 142 | + |
| 143 | + /// Return the procedure symbol if this is a call to a user defined |
| 144 | + /// procedure. |
| 145 | + const Fortran::semantics::Symbol *getProcedureSymbol() const; |
| 146 | + |
| 147 | + /// Add mlir::FuncOp entry block and map fir block arguments to Fortran dummy |
| 148 | + /// argument symbols. |
| 149 | + mlir::FuncOp addEntryBlockAndMapArguments(); |
| 150 | + |
| 151 | +private: |
| 152 | + Fortran::lower::pft::FunctionLikeUnit &funit; |
| 153 | +}; |
| 154 | + |
| 155 | +} // namespace Fortran::lower |
| 156 | + |
| 157 | +#endif // FORTRAN_LOWER_FIRBUILDER_H |
0 commit comments