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
32namespace fir {
33
34using TypeBuilderFunc = mlir::Type (*)(mlir::MLIRContext *);
35
36/// Get the LLVM IR dialect model for building a particular C++ type, `T`.
37template <typename T>
38TypeBuilderFunc getModel();
39
40template <>
41TypeBuilderFunc getModel<void *>() {
42 return [](mlir::MLIRContext *context) -> mlir::Type {
43 return mlir::LLVM::LLVMPointerType::get(context);
44 };
45}
46template <>
47TypeBuilderFunc getModel<unsigned>() {
48 return [](mlir::MLIRContext *context) -> mlir::Type {
49 return mlir::IntegerType::get(context, sizeof(unsigned) * 8);
50 };
51}
52template <>
53TypeBuilderFunc getModel<int>() {
54 return [](mlir::MLIRContext *context) -> mlir::Type {
55 return mlir::IntegerType::get(context, sizeof(int) * 8);
56 };
57}
58template <>
59TypeBuilderFunc getModel<unsigned long>() {
60 return [](mlir::MLIRContext *context) -> mlir::Type {
61 return mlir::IntegerType::get(context, sizeof(unsigned long) * 8);
62 };
63}
64template <>
65TypeBuilderFunc getModel<unsigned long long>() {
66 return [](mlir::MLIRContext *context) -> mlir::Type {
67 return mlir::IntegerType::get(context, sizeof(unsigned long long) * 8);
68 };
69}
70template <>
71TypeBuilderFunc getModel<long long>() {
72 return [](mlir::MLIRContext *context) -> mlir::Type {
73 return mlir::IntegerType::get(context, sizeof(long long) * 8);
74 };
75}
76template <>
77TypeBuilderFunc 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}
83template <>
84TypeBuilderFunc 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}
90template <>
91TypeBuilderFunc getModel<long>() {
92 return [](mlir::MLIRContext *context) -> mlir::Type {
93 return mlir::IntegerType::get(context, sizeof(long) * 8);
94 };
95}
96template <>
97TypeBuilderFunc 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}
103template <>
104TypeBuilderFunc
105getModel<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.
114template <int Field>
115static 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.
128template <int Field>
129static 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

source code of flang/lib/Optimizer/CodeGen/DescriptorModel.h