xref: /llvm-project/flang/include/flang/Optimizer/CodeGen/DescriptorModel.h (revision c91ba04328e1ded6f284469a7828d181324d4e30)
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