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.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 | TypeBuilderFunc getModel(); |
39 | |
40 | template <> |
41 | TypeBuilderFunc getModel<void *>() { |
42 | return [](mlir::MLIRContext *context) -> mlir::Type { |
43 | return mlir::LLVM::LLVMPointerType::get(context); |
44 | }; |
45 | } |
46 | template <> |
47 | TypeBuilderFunc getModel<unsigned>() { |
48 | return [](mlir::MLIRContext *context) -> mlir::Type { |
49 | return mlir::IntegerType::get(context, sizeof(unsigned) * 8); |
50 | }; |
51 | } |
52 | template <> |
53 | TypeBuilderFunc getModel<int>() { |
54 | return [](mlir::MLIRContext *context) -> mlir::Type { |
55 | return mlir::IntegerType::get(context, sizeof(int) * 8); |
56 | }; |
57 | } |
58 | template <> |
59 | 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 | 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 | 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 | 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 | 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 | TypeBuilderFunc getModel<long>() { |
92 | return [](mlir::MLIRContext *context) -> mlir::Type { |
93 | return mlir::IntegerType::get(context, sizeof(long) * 8); |
94 | }; |
95 | } |
96 | template <> |
97 | 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 | 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 | |