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>
getDescFieldTypeModel()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>
getExtendedDescFieldTypeModel()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