//===-- RTBuilder.h ---------------------------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// /// /// \file /// This file defines some C++17 template classes that are used to convert the /// signatures of plain old C functions into a model that can be used to /// generate MLIR calls to those functions. This can be used to autogenerate /// tables at compiler compile-time to call runtime support code. /// //===----------------------------------------------------------------------===// #ifndef FORTRAN_LOWER_RTBUILDER_H #define FORTRAN_LOWER_RTBUILDER_H #include "flang/Lower/ConvertType.h" #include "flang/Optimizer/Dialect/FIRType.h" #include "mlir/IR/BuiltinTypes.h" #include "mlir/IR/MLIRContext.h" #include "llvm/ADT/SmallVector.h" #include // List the runtime headers we want to be able to dissect #include "../../runtime/io-api.h" namespace Fortran::lower { using TypeBuilderFunc = mlir::Type (*)(mlir::MLIRContext *); using FuncTypeBuilderFunc = mlir::FunctionType (*)(mlir::MLIRContext *); //===----------------------------------------------------------------------===// // Type builder models //===----------------------------------------------------------------------===// /// Return a function that returns the type signature model for the type `T` /// when provided an MLIRContext*. This allows one to translate C(++) function /// signatures from runtime header files to MLIR signatures into a static table /// at compile-time. /// /// For example, when `T` is `int`, return a function that returns the MLIR /// standard type `i32` when `sizeof(int)` is 4. template static constexpr TypeBuilderFunc getModel(); template <> constexpr TypeBuilderFunc getModel() { return [](mlir::MLIRContext *context) -> mlir::Type { return mlir::IntegerType::get(8 * sizeof(int), context); }; } template <> constexpr TypeBuilderFunc getModel() { return [](mlir::MLIRContext *context) -> mlir::Type { TypeBuilderFunc f{getModel()}; return fir::ReferenceType::get(f(context)); }; } template <> constexpr TypeBuilderFunc getModel() { return [](mlir::MLIRContext *context) -> mlir::Type { return mlir::IntegerType::get(8 * sizeof(Fortran::runtime::io::Iostat), context); }; } template <> constexpr TypeBuilderFunc getModel() { return [](mlir::MLIRContext *context) -> mlir::Type { return fir::ReferenceType::get(mlir::IntegerType::get(8, context)); }; } template <> constexpr TypeBuilderFunc getModel() { return getModel(); } template <> constexpr TypeBuilderFunc getModel() { return [](mlir::MLIRContext *context) -> mlir::Type { return fir::ReferenceType::get(mlir::IntegerType::get(16, context)); }; } template <> constexpr TypeBuilderFunc getModel() { return [](mlir::MLIRContext *context) -> mlir::Type { return fir::ReferenceType::get(mlir::IntegerType::get(32, context)); }; } template <> constexpr TypeBuilderFunc getModel() { return [](mlir::MLIRContext *context) -> mlir::Type { return fir::ReferenceType::get( fir::PointerType::get(mlir::IntegerType::get(8, context))); }; } template <> constexpr TypeBuilderFunc getModel() { return [](mlir::MLIRContext *context) -> mlir::Type { return mlir::IntegerType::get(64, context); }; } template <> constexpr TypeBuilderFunc getModel() { return [](mlir::MLIRContext *context) -> mlir::Type { TypeBuilderFunc f{getModel()}; return fir::ReferenceType::get(f(context)); }; } template <> constexpr TypeBuilderFunc getModel() { return [](mlir::MLIRContext *context) -> mlir::Type { return mlir::IntegerType::get(8 * sizeof(std::size_t), context); }; } template <> constexpr TypeBuilderFunc getModel() { return getModel(); } template <> constexpr TypeBuilderFunc getModel() { return [](mlir::MLIRContext *context) -> mlir::Type { return mlir::FloatType::getF64(context); }; } template <> constexpr TypeBuilderFunc getModel() { return [](mlir::MLIRContext *context) -> mlir::Type { TypeBuilderFunc f{getModel()}; return fir::ReferenceType::get(f(context)); }; } template <> constexpr TypeBuilderFunc getModel() { return [](mlir::MLIRContext *context) -> mlir::Type { return mlir::FloatType::getF32(context); }; } template <> constexpr TypeBuilderFunc getModel() { return [](mlir::MLIRContext *context) -> mlir::Type { TypeBuilderFunc f{getModel()}; return fir::ReferenceType::get(f(context)); }; } template <> constexpr TypeBuilderFunc getModel() { return [](mlir::MLIRContext *context) -> mlir::Type { return mlir::IntegerType::get(1, context); }; } template <> constexpr TypeBuilderFunc getModel() { return [](mlir::MLIRContext *context) -> mlir::Type { TypeBuilderFunc f{getModel()}; return fir::ReferenceType::get(f(context)); }; } template <> constexpr TypeBuilderFunc getModel() { return [](mlir::MLIRContext *context) -> mlir::Type { return fir::BoxType::get(mlir::NoneType::get(context)); }; } template <> constexpr TypeBuilderFunc getModel() { return [](mlir::MLIRContext *context) -> mlir::Type { // FIXME: a namelist group must be some well-defined data structure, use a // tuple as a proxy for the moment return mlir::TupleType::get(context); }; } template <> constexpr TypeBuilderFunc getModel() { return [](mlir::MLIRContext *context) -> mlir::Type { return mlir::NoneType::get(context); }; } template struct RuntimeTableKey; template struct RuntimeTableKey { static constexpr FuncTypeBuilderFunc getTypeModel() { return [](mlir::MLIRContext *ctxt) { TypeBuilderFunc ret = getModel(); std::array args = {getModel()...}; mlir::Type retTy = ret(ctxt); llvm::SmallVector argTys; for (auto f : args) argTys.push_back(f(ctxt)); return mlir::FunctionType::get(argTys, {retTy}, ctxt); }; } }; //===----------------------------------------------------------------------===// // Runtime table building (constexpr folded) //===----------------------------------------------------------------------===// template using RuntimeIdentifier = std::integer_sequence; namespace details { template static constexpr std::integer_sequence concat(std::integer_sequence, std::integer_sequence) { return {}; } template static constexpr auto concat(std::integer_sequence, std::integer_sequence, Cs...) { return concat(std::integer_sequence{}, Cs{}...); } template static constexpr std::integer_sequence concat(std::integer_sequence) { return {}; } template static constexpr auto filterZero(std::integer_sequence) { if constexpr (a != 0) { return std::integer_sequence{}; } else { return std::integer_sequence{}; } } template static constexpr auto filter(std::integer_sequence) { if constexpr (sizeof...(b) > 0) { return details::concat(filterZero(std::integer_sequence{})...); } else { return std::integer_sequence{}; } } } // namespace details template struct RuntimeTableEntry; template struct RuntimeTableEntry, RuntimeIdentifier> { static constexpr FuncTypeBuilderFunc getTypeModel() { return RuntimeTableKey::getTypeModel(); } static constexpr const char name[sizeof...(Cs) + 1] = {Cs..., '\0'}; }; #undef E #define E(L, I) (I < sizeof(L) / sizeof(*L) ? L[I] : 0) #define QuoteKey(X) #X #define MacroExpandKey(X) \ E(X, 0), E(X, 1), E(X, 2), E(X, 3), E(X, 4), E(X, 5), E(X, 6), E(X, 7), \ E(X, 8), E(X, 9), E(X, 10), E(X, 11), E(X, 12), E(X, 13), E(X, 14), \ E(X, 15), E(X, 16), E(X, 17), E(X, 18), E(X, 19), E(X, 20), E(X, 21), \ E(X, 22), E(X, 23), E(X, 24), E(X, 25), E(X, 26), E(X, 27), E(X, 28), \ E(X, 29), E(X, 30), E(X, 31), E(X, 32), E(X, 33), E(X, 34), E(X, 35), \ E(X, 36), E(X, 37), E(X, 38), E(X, 39), E(X, 40), E(X, 41), E(X, 42), \ E(X, 43), E(X, 44), E(X, 45), E(X, 46), E(X, 47), E(X, 48), E(X, 49) #define ExpandKey(X) MacroExpandKey(QuoteKey(X)) #define FullSeq(X) std::integer_sequence #define AsSequence(X) decltype(Fortran::lower::details::filter(FullSeq(X){})) #define mkKey(X) \ Fortran::lower::RuntimeTableEntry< \ Fortran::lower::RuntimeTableKey, AsSequence(X)> } // namespace Fortran::lower #endif // FORTRAN_LOWER_RTBUILDER_H