1 //===-- DescriptorModel.h -- model of descriptors for codegen ---*- 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 // LLVM IR dialect models of C++ types. 9 // 10 // This supplies a set of model builders to decompose the C declaration of a 11 // descriptor (as encoded in ISO_Fortran_binding.h and elsewhere) and 12 // reconstruct that type in the LLVM IR dialect. 13 // 14 // TODO: It is understood that this is deeply incorrect as far as building a 15 // portability layer for cross-compilation as these reflected types are those of 16 // the build machine and not necessarily that of either the host or the target. 17 // This assumption that build == host == target is actually pervasive across the 18 // compiler (https://llvm.org/PR52418). 19 // 20 //===----------------------------------------------------------------------===// 21 22 #ifndef OPTIMIZER_DESCRIPTOR_MODEL_H 23 #define OPTIMIZER_DESCRIPTOR_MODEL_H 24 25 #include "flang/ISO_Fortran_binding_wrapper.h" 26 #include "flang/Runtime/descriptor-consts.h" 27 #include "mlir/Dialect/LLVMIR/LLVMTypes.h" 28 #include "mlir/IR/BuiltinTypes.h" 29 #include "llvm/Support/ErrorHandling.h" 30 #include <tuple> 31 32 namespace fir { 33 34 using TypeBuilderFunc = mlir::Type (*)(mlir::MLIRContext *); 35 36 /// Get the LLVM IR dialect model for building a particular C++ type, `T`. 37 template <typename T> 38 static TypeBuilderFunc getModel(); 39 40 template <> 41 constexpr TypeBuilderFunc getModel<void *>() { 42 return [](mlir::MLIRContext *context) -> mlir::Type { 43 return mlir::LLVM::LLVMPointerType::get(context); 44 }; 45 } 46 template <> 47 constexpr TypeBuilderFunc getModel<unsigned>() { 48 return [](mlir::MLIRContext *context) -> mlir::Type { 49 return mlir::IntegerType::get(context, sizeof(unsigned) * 8); 50 }; 51 } 52 template <> 53 constexpr TypeBuilderFunc getModel<int>() { 54 return [](mlir::MLIRContext *context) -> mlir::Type { 55 return mlir::IntegerType::get(context, sizeof(int) * 8); 56 }; 57 } 58 template <> 59 constexpr TypeBuilderFunc getModel<unsigned long>() { 60 return [](mlir::MLIRContext *context) -> mlir::Type { 61 return mlir::IntegerType::get(context, sizeof(unsigned long) * 8); 62 }; 63 } 64 template <> 65 constexpr TypeBuilderFunc getModel<unsigned long long>() { 66 return [](mlir::MLIRContext *context) -> mlir::Type { 67 return mlir::IntegerType::get(context, sizeof(unsigned long long) * 8); 68 }; 69 } 70 template <> 71 constexpr TypeBuilderFunc getModel<long long>() { 72 return [](mlir::MLIRContext *context) -> mlir::Type { 73 return mlir::IntegerType::get(context, sizeof(long long) * 8); 74 }; 75 } 76 template <> 77 constexpr TypeBuilderFunc getModel<Fortran::ISO::CFI_rank_t>() { 78 return [](mlir::MLIRContext *context) -> mlir::Type { 79 return mlir::IntegerType::get(context, 80 sizeof(Fortran::ISO::CFI_rank_t) * 8); 81 }; 82 } 83 template <> 84 constexpr TypeBuilderFunc getModel<Fortran::ISO::CFI_type_t>() { 85 return [](mlir::MLIRContext *context) -> mlir::Type { 86 return mlir::IntegerType::get(context, 87 sizeof(Fortran::ISO::CFI_type_t) * 8); 88 }; 89 } 90 template <> 91 constexpr TypeBuilderFunc getModel<long>() { 92 return [](mlir::MLIRContext *context) -> mlir::Type { 93 return mlir::IntegerType::get(context, sizeof(long) * 8); 94 }; 95 } 96 template <> 97 constexpr TypeBuilderFunc getModel<Fortran::ISO::CFI_dim_t>() { 98 return [](mlir::MLIRContext *context) -> mlir::Type { 99 auto indexTy = getModel<Fortran::ISO::CFI_index_t>()(context); 100 return mlir::LLVM::LLVMArrayType::get(indexTy, 3); 101 }; 102 } 103 template <> 104 constexpr TypeBuilderFunc 105 getModel<Fortran::ISO::cfi_internal::FlexibleArray<Fortran::ISO::CFI_dim_t>>() { 106 return getModel<Fortran::ISO::CFI_dim_t>(); 107 } 108 109 //===----------------------------------------------------------------------===// 110 // Descriptor reflection 111 //===----------------------------------------------------------------------===// 112 113 /// Get the type model of the field number `Field` in an ISO CFI descriptor. 114 template <int Field> 115 static constexpr TypeBuilderFunc getDescFieldTypeModel() { 116 Fortran::ISO::CFI_cdesc_t dummyDesc{}; 117 // check that the descriptor is exactly 8 fields as specified in CFI_cdesc_t 118 // in flang/include/flang/ISO_Fortran_binding.h. 119 auto [a, b, c, d, e, f, g, h] = dummyDesc; 120 auto tup = std::tie(a, b, c, d, e, f, g, h); 121 auto field = std::get<Field>(tup); 122 return getModel<decltype(field)>(); 123 } 124 125 /// An extended descriptor is defined by a class in runtime/descriptor.h. The 126 /// three fields in the class are hard-coded here, unlike the reflection used on 127 /// the ISO parts, which are a POD. 128 template <int Field> 129 static constexpr TypeBuilderFunc getExtendedDescFieldTypeModel() { 130 if constexpr (Field == 8) { 131 return getModel<void *>(); 132 } else if constexpr (Field == 9) { 133 return getModel<Fortran::runtime::typeInfo::TypeParameterValue>(); 134 } else { 135 llvm_unreachable("extended ISO descriptor only has 10 fields"); 136 } 137 } 138 139 } // namespace fir 140 141 #endif // OPTIMIZER_DESCRIPTOR_MODEL_H 142