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.h" 26 #include "flang/Runtime/descriptor.h" 27 #include "mlir/Dialect/LLVMIR/LLVMTypes.h" 28 #include "llvm/Support/ErrorHandling.h" 29 #include <tuple> 30 31 namespace fir { 32 33 using TypeBuilderFunc = mlir::Type (*)(mlir::MLIRContext *); 34 35 /// Get the LLVM IR dialect model for building a particular C++ type, `T`. 36 template <typename T> 37 TypeBuilderFunc getModel(); 38 39 template <> 40 TypeBuilderFunc getModel<void *>() { 41 return [](mlir::MLIRContext *context) -> mlir::Type { 42 return mlir::LLVM::LLVMPointerType::get(mlir::IntegerType::get(context, 8)); 43 }; 44 } 45 template <> 46 TypeBuilderFunc getModel<unsigned>() { 47 return [](mlir::MLIRContext *context) -> mlir::Type { 48 return mlir::IntegerType::get(context, sizeof(unsigned) * 8); 49 }; 50 } 51 template <> 52 TypeBuilderFunc getModel<int>() { 53 return [](mlir::MLIRContext *context) -> mlir::Type { 54 return mlir::IntegerType::get(context, sizeof(int) * 8); 55 }; 56 } 57 template <> 58 TypeBuilderFunc getModel<unsigned long>() { 59 return [](mlir::MLIRContext *context) -> mlir::Type { 60 return mlir::IntegerType::get(context, sizeof(unsigned long) * 8); 61 }; 62 } 63 template <> 64 TypeBuilderFunc getModel<unsigned long long>() { 65 return [](mlir::MLIRContext *context) -> mlir::Type { 66 return mlir::IntegerType::get(context, sizeof(unsigned long long) * 8); 67 }; 68 } 69 template <> 70 TypeBuilderFunc getModel<long long>() { 71 return [](mlir::MLIRContext *context) -> mlir::Type { 72 return mlir::IntegerType::get(context, sizeof(long long) * 8); 73 }; 74 } 75 template <> 76 TypeBuilderFunc getModel<Fortran::ISO::CFI_rank_t>() { 77 return [](mlir::MLIRContext *context) -> mlir::Type { 78 return mlir::IntegerType::get(context, 79 sizeof(Fortran::ISO::CFI_rank_t) * 8); 80 }; 81 } 82 template <> 83 TypeBuilderFunc getModel<Fortran::ISO::CFI_type_t>() { 84 return [](mlir::MLIRContext *context) -> mlir::Type { 85 return mlir::IntegerType::get(context, 86 sizeof(Fortran::ISO::CFI_type_t) * 8); 87 }; 88 } 89 template <> 90 TypeBuilderFunc getModel<long>() { 91 return [](mlir::MLIRContext *context) -> mlir::Type { 92 return mlir::IntegerType::get(context, sizeof(long) * 8); 93 }; 94 } 95 template <> 96 TypeBuilderFunc getModel<Fortran::ISO::CFI_dim_t>() { 97 return [](mlir::MLIRContext *context) -> mlir::Type { 98 auto indexTy = getModel<Fortran::ISO::CFI_index_t>()(context); 99 return mlir::LLVM::LLVMArrayType::get(indexTy, 3); 100 }; 101 } 102 template <> 103 TypeBuilderFunc 104 getModel<Fortran::ISO::cfi_internal::FlexibleArray<Fortran::ISO::CFI_dim_t>>() { 105 return getModel<Fortran::ISO::CFI_dim_t>(); 106 } 107 108 //===----------------------------------------------------------------------===// 109 // Descriptor reflection 110 //===----------------------------------------------------------------------===// 111 112 /// Get the type model of the field number `Field` in an ISO CFI descriptor. 113 template <int Field> 114 static constexpr TypeBuilderFunc getDescFieldTypeModel() { 115 Fortran::ISO::Fortran_2018::CFI_cdesc_t dummyDesc{}; 116 // check that the descriptor is exactly 8 fields as specified in CFI_cdesc_t 117 // in flang/include/flang/ISO_Fortran_binding.h. 118 auto [a, b, c, d, e, f, g, h] = dummyDesc; 119 auto tup = std::tie(a, b, c, d, e, f, g, h); 120 auto field = std::get<Field>(tup); 121 return getModel<decltype(field)>(); 122 } 123 124 /// An extended descriptor is defined by a class in runtime/descriptor.h. The 125 /// three fields in the class are hard-coded here, unlike the reflection used on 126 /// the ISO parts, which are a POD. 127 template <int Field> 128 static constexpr TypeBuilderFunc getExtendedDescFieldTypeModel() { 129 if constexpr (Field == 8) { 130 return getModel<void *>(); 131 } else if constexpr (Field == 9) { 132 return getModel<Fortran::runtime::typeInfo::TypeParameterValue>(); 133 } else { 134 llvm_unreachable("extended ISO descriptor only has 10 fields"); 135 } 136 } 137 138 } // namespace fir 139 140 #endif // OPTIMIZER_DESCRIPTOR_MODEL_H 141