1 //===-- RTBuilder.h ---------------------------------------------*- 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 /// \file 10 /// This file defines some C++17 template classes that are used to convert the 11 /// signatures of plain old C functions into a model that can be used to 12 /// generate MLIR calls to those functions. This can be used to autogenerate 13 /// tables at compiler compile-time to call runtime support code. 14 /// 15 //===----------------------------------------------------------------------===// 16 17 #ifndef FORTRAN_LOWER_RTBUILDER_H 18 #define FORTRAN_LOWER_RTBUILDER_H 19 20 #include "flang/Lower/ConvertType.h" 21 #include "flang/Optimizer/Dialect/FIRType.h" 22 #include "mlir/IR/BuiltinTypes.h" 23 #include "mlir/IR/MLIRContext.h" 24 #include "llvm/ADT/SmallVector.h" 25 #include <functional> 26 27 // List the runtime headers we want to be able to dissect 28 #include "../../runtime/io-api.h" 29 30 namespace Fortran::lower { 31 32 using TypeBuilderFunc = mlir::Type (*)(mlir::MLIRContext *); 33 using FuncTypeBuilderFunc = mlir::FunctionType (*)(mlir::MLIRContext *); 34 35 //===----------------------------------------------------------------------===// 36 // Type builder models 37 //===----------------------------------------------------------------------===// 38 39 /// Return a function that returns the type signature model for the type `T` 40 /// when provided an MLIRContext*. This allows one to translate C(++) function 41 /// signatures from runtime header files to MLIR signatures into a static table 42 /// at compile-time. 43 /// 44 /// For example, when `T` is `int`, return a function that returns the MLIR 45 /// standard type `i32` when `sizeof(int)` is 4. 46 template <typename T> 47 static constexpr TypeBuilderFunc getModel(); 48 template <> 49 constexpr TypeBuilderFunc getModel<int>() { 50 return [](mlir::MLIRContext *context) -> mlir::Type { 51 return mlir::IntegerType::get(8 * sizeof(int), context); 52 }; 53 } 54 template <> 55 constexpr TypeBuilderFunc getModel<int &>() { 56 return [](mlir::MLIRContext *context) -> mlir::Type { 57 TypeBuilderFunc f{getModel<int>()}; 58 return fir::ReferenceType::get(f(context)); 59 }; 60 } 61 template <> 62 constexpr TypeBuilderFunc getModel<Fortran::runtime::io::Iostat>() { 63 return [](mlir::MLIRContext *context) -> mlir::Type { 64 return mlir::IntegerType::get(8 * sizeof(Fortran::runtime::io::Iostat), 65 context); 66 }; 67 } 68 template <> 69 constexpr TypeBuilderFunc getModel<char *>() { 70 return [](mlir::MLIRContext *context) -> mlir::Type { 71 return fir::ReferenceType::get(mlir::IntegerType::get(8, context)); 72 }; 73 } 74 template <> 75 constexpr TypeBuilderFunc getModel<const char *>() { 76 return getModel<char *>(); 77 } 78 template <> 79 constexpr TypeBuilderFunc getModel<const char16_t *>() { 80 return [](mlir::MLIRContext *context) -> mlir::Type { 81 return fir::ReferenceType::get(mlir::IntegerType::get(16, context)); 82 }; 83 } 84 template <> 85 constexpr TypeBuilderFunc getModel<const char32_t *>() { 86 return [](mlir::MLIRContext *context) -> mlir::Type { 87 return fir::ReferenceType::get(mlir::IntegerType::get(32, context)); 88 }; 89 } 90 template <> 91 constexpr TypeBuilderFunc getModel<void **>() { 92 return [](mlir::MLIRContext *context) -> mlir::Type { 93 return fir::ReferenceType::get( 94 fir::PointerType::get(mlir::IntegerType::get(8, context))); 95 }; 96 } 97 template <> 98 constexpr TypeBuilderFunc getModel<std::int64_t>() { 99 return [](mlir::MLIRContext *context) -> mlir::Type { 100 return mlir::IntegerType::get(64, context); 101 }; 102 } 103 template <> 104 constexpr TypeBuilderFunc getModel<std::int64_t &>() { 105 return [](mlir::MLIRContext *context) -> mlir::Type { 106 TypeBuilderFunc f{getModel<std::int64_t>()}; 107 return fir::ReferenceType::get(f(context)); 108 }; 109 } 110 template <> 111 constexpr TypeBuilderFunc getModel<std::size_t>() { 112 return [](mlir::MLIRContext *context) -> mlir::Type { 113 return mlir::IntegerType::get(8 * sizeof(std::size_t), context); 114 }; 115 } 116 template <> 117 constexpr TypeBuilderFunc getModel<Fortran::runtime::io::IoStatementState *>() { 118 return getModel<char *>(); 119 } 120 template <> 121 constexpr TypeBuilderFunc getModel<double>() { 122 return [](mlir::MLIRContext *context) -> mlir::Type { 123 return mlir::FloatType::getF64(context); 124 }; 125 } 126 template <> 127 constexpr TypeBuilderFunc getModel<double &>() { 128 return [](mlir::MLIRContext *context) -> mlir::Type { 129 TypeBuilderFunc f{getModel<double>()}; 130 return fir::ReferenceType::get(f(context)); 131 }; 132 } 133 template <> 134 constexpr TypeBuilderFunc getModel<float>() { 135 return [](mlir::MLIRContext *context) -> mlir::Type { 136 return mlir::FloatType::getF32(context); 137 }; 138 } 139 template <> 140 constexpr TypeBuilderFunc getModel<float &>() { 141 return [](mlir::MLIRContext *context) -> mlir::Type { 142 TypeBuilderFunc f{getModel<float>()}; 143 return fir::ReferenceType::get(f(context)); 144 }; 145 } 146 template <> 147 constexpr TypeBuilderFunc getModel<bool>() { 148 return [](mlir::MLIRContext *context) -> mlir::Type { 149 return mlir::IntegerType::get(1, context); 150 }; 151 } 152 template <> 153 constexpr TypeBuilderFunc getModel<bool &>() { 154 return [](mlir::MLIRContext *context) -> mlir::Type { 155 TypeBuilderFunc f{getModel<bool>()}; 156 return fir::ReferenceType::get(f(context)); 157 }; 158 } 159 160 template <> 161 constexpr TypeBuilderFunc getModel<const Fortran::runtime::Descriptor &>() { 162 return [](mlir::MLIRContext *context) -> mlir::Type { 163 return fir::BoxType::get(mlir::NoneType::get(context)); 164 }; 165 } 166 template <> 167 constexpr TypeBuilderFunc getModel<const Fortran::runtime::NamelistGroup &>() { 168 return [](mlir::MLIRContext *context) -> mlir::Type { 169 // FIXME: a namelist group must be some well-defined data structure, use a 170 // tuple as a proxy for the moment 171 return mlir::TupleType::get(context); 172 }; 173 } 174 template <> 175 constexpr TypeBuilderFunc getModel<void>() { 176 return [](mlir::MLIRContext *context) -> mlir::Type { 177 return mlir::NoneType::get(context); 178 }; 179 } 180 181 template <typename...> 182 struct RuntimeTableKey; 183 template <typename RT, typename... ATs> 184 struct RuntimeTableKey<RT(ATs...)> { 185 static constexpr FuncTypeBuilderFunc getTypeModel() { 186 return [](mlir::MLIRContext *ctxt) { 187 TypeBuilderFunc ret = getModel<RT>(); 188 std::array<TypeBuilderFunc, sizeof...(ATs)> args = {getModel<ATs>()...}; 189 mlir::Type retTy = ret(ctxt); 190 llvm::SmallVector<mlir::Type, sizeof...(ATs)> argTys; 191 for (auto f : args) 192 argTys.push_back(f(ctxt)); 193 return mlir::FunctionType::get(argTys, {retTy}, ctxt); 194 }; 195 } 196 }; 197 198 //===----------------------------------------------------------------------===// 199 // Runtime table building (constexpr folded) 200 //===----------------------------------------------------------------------===// 201 202 template <char... Cs> 203 using RuntimeIdentifier = std::integer_sequence<char, Cs...>; 204 205 namespace details { 206 template <typename T, T... As, T... Bs> 207 static constexpr std::integer_sequence<T, As..., Bs...> 208 concat(std::integer_sequence<T, As...>, std::integer_sequence<T, Bs...>) { 209 return {}; 210 } 211 template <typename T, T... As, T... Bs, typename... Cs> 212 static constexpr auto concat(std::integer_sequence<T, As...>, 213 std::integer_sequence<T, Bs...>, Cs...) { 214 return concat(std::integer_sequence<T, As..., Bs...>{}, Cs{}...); 215 } 216 template <typename T> 217 static constexpr std::integer_sequence<T> concat(std::integer_sequence<T>) { 218 return {}; 219 } 220 template <typename T, T a> 221 static constexpr auto filterZero(std::integer_sequence<T, a>) { 222 if constexpr (a != 0) { 223 return std::integer_sequence<T, a>{}; 224 } else { 225 return std::integer_sequence<T>{}; 226 } 227 } 228 template <typename T, T... b> 229 static constexpr auto filter(std::integer_sequence<T, b...>) { 230 if constexpr (sizeof...(b) > 0) { 231 return details::concat(filterZero(std::integer_sequence<T, b>{})...); 232 } else { 233 return std::integer_sequence<T>{}; 234 } 235 } 236 } // namespace details 237 238 template <typename...> 239 struct RuntimeTableEntry; 240 template <typename KT, char... Cs> 241 struct RuntimeTableEntry<RuntimeTableKey<KT>, RuntimeIdentifier<Cs...>> { 242 static constexpr FuncTypeBuilderFunc getTypeModel() { 243 return RuntimeTableKey<KT>::getTypeModel(); 244 } 245 static constexpr const char name[sizeof...(Cs) + 1] = {Cs..., '\0'}; 246 }; 247 248 #undef E 249 #define E(L, I) (I < sizeof(L) / sizeof(*L) ? L[I] : 0) 250 #define QuoteKey(X) #X 251 #define MacroExpandKey(X) \ 252 E(X, 0), E(X, 1), E(X, 2), E(X, 3), E(X, 4), E(X, 5), E(X, 6), E(X, 7), \ 253 E(X, 8), E(X, 9), E(X, 10), E(X, 11), E(X, 12), E(X, 13), E(X, 14), \ 254 E(X, 15), E(X, 16), E(X, 17), E(X, 18), E(X, 19), E(X, 20), E(X, 21), \ 255 E(X, 22), E(X, 23), E(X, 24), E(X, 25), E(X, 26), E(X, 27), E(X, 28), \ 256 E(X, 29), E(X, 30), E(X, 31), E(X, 32), E(X, 33), E(X, 34), E(X, 35), \ 257 E(X, 36), E(X, 37), E(X, 38), E(X, 39), E(X, 40), E(X, 41), E(X, 42), \ 258 E(X, 43), E(X, 44), E(X, 45), E(X, 46), E(X, 47), E(X, 48), E(X, 49) 259 #define ExpandKey(X) MacroExpandKey(QuoteKey(X)) 260 #define FullSeq(X) std::integer_sequence<char, ExpandKey(X)> 261 #define AsSequence(X) decltype(Fortran::lower::details::filter(FullSeq(X){})) 262 #define mkKey(X) \ 263 Fortran::lower::RuntimeTableEntry< \ 264 Fortran::lower::RuntimeTableKey<decltype(X)>, AsSequence(X)> 265 266 } // namespace Fortran::lower 267 268 #endif // FORTRAN_LOWER_RTBUILDER_H 269