FLANG
Utils.h
1//===-- Optimizer/Support/Utils.h -------------------------------*- 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//
9// Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef FORTRAN_OPTIMIZER_SUPPORT_UTILS_H
14#define FORTRAN_OPTIMIZER_SUPPORT_UTILS_H
15
16#include "flang/Optimizer/Builder/FIRBuilder.h"
17#include "flang/Optimizer/Builder/Todo.h"
18#include "flang/Optimizer/Dialect/CUF/Attributes/CUFAttr.h"
19#include "flang/Optimizer/Dialect/FIROps.h"
20#include "flang/Optimizer/Dialect/FIRType.h"
21#include "flang/Optimizer/Support/FatalError.h"
22#include "flang/Support/default-kinds.h"
23#include "mlir/Dialect/Arith/IR/Arith.h"
24#include "mlir/Dialect/Func/IR/FuncOps.h"
25#include "mlir/IR/BuiltinAttributes.h"
26#include "mlir/IR/BuiltinOps.h"
27#include "llvm/ADT/DenseMap.h"
28#include "llvm/ADT/StringRef.h"
29
30#include "flang/Optimizer/CodeGen/TypeConverter.h"
31
32namespace fir {
34inline std::int64_t toInt(mlir::arith::ConstantOp cop) {
35 return mlir::cast<mlir::IntegerAttr>(cop.getValue())
36 .getValue()
37 .getSExtValue();
38}
39
40// Translate front-end KINDs for use in the IR and code gen.
41inline std::vector<fir::KindTy>
42fromDefaultKinds(const Fortran::common::IntrinsicTypeDefaultKinds &defKinds) {
43 return {static_cast<fir::KindTy>(defKinds.GetDefaultKind(
44 Fortran::common::TypeCategory::Character)),
45 static_cast<fir::KindTy>(
46 defKinds.GetDefaultKind(Fortran::common::TypeCategory::Complex)),
47 static_cast<fir::KindTy>(defKinds.doublePrecisionKind()),
48 static_cast<fir::KindTy>(
49 defKinds.GetDefaultKind(Fortran::common::TypeCategory::Integer)),
50 static_cast<fir::KindTy>(
51 defKinds.GetDefaultKind(Fortran::common::TypeCategory::Logical)),
52 static_cast<fir::KindTy>(
53 defKinds.GetDefaultKind(Fortran::common::TypeCategory::Real))};
54}
55
56inline std::string mlirTypeToString(mlir::Type type) {
57 std::string result{};
58 llvm::raw_string_ostream sstream(result);
59 sstream << type;
60 return result;
61}
62
63inline std::optional<int> mlirFloatTypeToKind(mlir::Type type) {
64 if (type.isF16())
65 return 2;
66 else if (type.isBF16())
67 return 3;
68 else if (type.isF32())
69 return 4;
70 else if (type.isF64())
71 return 8;
72 else if (type.isF80())
73 return 10;
74 else if (type.isF128())
75 return 16;
76 return std::nullopt;
77}
78
79inline std::string mlirTypeToIntrinsicFortran(fir::FirOpBuilder &builder,
80 mlir::Type type,
81 mlir::Location loc,
82 const llvm::Twine &name) {
83 if (auto floatTy = mlir::dyn_cast<mlir::FloatType>(type)) {
84 if (std::optional<int> kind = mlirFloatTypeToKind(type))
85 return "REAL(KIND="s + std::to_string(*kind) + ")";
86 } else if (auto cplxTy = mlir::dyn_cast<mlir::ComplexType>(type)) {
87 if (std::optional<int> kind = mlirFloatTypeToKind(cplxTy.getElementType()))
88 return "COMPLEX(KIND+"s + std::to_string(*kind) + ")";
89 } else if (type.isUnsignedInteger()) {
90 if (type.isInteger(8))
91 return "UNSIGNED(KIND=1)";
92 else if (type.isInteger(16))
93 return "UNSIGNED(KIND=2)";
94 else if (type.isInteger(32))
95 return "UNSIGNED(KIND=4)";
96 else if (type.isInteger(64))
97 return "UNSIGNED(KIND=8)";
98 else if (type.isInteger(128))
99 return "UNSIGNED(KIND=16)";
100 } else if (type.isInteger(8))
101 return "INTEGER(KIND=1)";
102 else if (type.isInteger(16))
103 return "INTEGER(KIND=2)";
104 else if (type.isInteger(32))
105 return "INTEGER(KIND=4)";
106 else if (type.isInteger(64))
107 return "INTEGER(KIND=8)";
108 else if (type.isInteger(128))
109 return "INTEGER(KIND=16)";
110 else if (type == fir::LogicalType::get(builder.getContext(), 1))
111 return "LOGICAL(KIND=1)";
112 else if (type == fir::LogicalType::get(builder.getContext(), 2))
113 return "LOGICAL(KIND=2)";
114 else if (type == fir::LogicalType::get(builder.getContext(), 4))
115 return "LOGICAL(KIND=4)";
116 else if (type == fir::LogicalType::get(builder.getContext(), 8))
117 return "LOGICAL(KIND=8)";
118
119 fir::emitFatalError(loc, "unsupported type in " + name + ": " +
120 fir::mlirTypeToString(type));
121}
122
123inline void intrinsicTypeTODO(fir::FirOpBuilder &builder, mlir::Type type,
124 mlir::Location loc,
125 const llvm::Twine &intrinsicName) {
126 TODO(loc,
127 "intrinsic: " +
128 fir::mlirTypeToIntrinsicFortran(builder, type, loc, intrinsicName) +
129 " in " + intrinsicName);
130}
131
132inline void intrinsicTypeTODO2(fir::FirOpBuilder &builder, mlir::Type type1,
133 mlir::Type type2, mlir::Location loc,
134 const llvm::Twine &intrinsicName) {
135 TODO(loc,
136 "intrinsic: {" +
137 fir::mlirTypeToIntrinsicFortran(builder, type2, loc, intrinsicName) +
138 ", " +
139 fir::mlirTypeToIntrinsicFortran(builder, type2, loc, intrinsicName) +
140 "} in " + intrinsicName);
141}
142
143inline std::pair<Fortran::common::TypeCategory, KindMapping::KindTy>
144mlirTypeToCategoryKind(mlir::Location loc, mlir::Type type) {
145 if (auto floatTy = mlir::dyn_cast<mlir::FloatType>(type)) {
146 if (std::optional<int> kind = mlirFloatTypeToKind(type))
147 return {Fortran::common::TypeCategory::Real, *kind};
148 } else if (auto cplxTy = mlir::dyn_cast<mlir::ComplexType>(type)) {
149 if (std::optional<int> kind = mlirFloatTypeToKind(cplxTy.getElementType()))
150 return {Fortran::common::TypeCategory::Complex, *kind};
151 } else if (type.isInteger(8))
152 return {type.isUnsignedInteger() ? Fortran::common::TypeCategory::Unsigned
153 : Fortran::common::TypeCategory::Integer,
154 1};
155 else if (type.isInteger(16))
156 return {type.isUnsignedInteger() ? Fortran::common::TypeCategory::Unsigned
157 : Fortran::common::TypeCategory::Integer,
158 2};
159 else if (type.isInteger(32))
160 return {type.isUnsignedInteger() ? Fortran::common::TypeCategory::Unsigned
161 : Fortran::common::TypeCategory::Integer,
162 4};
163 else if (type.isInteger(64))
164 return {type.isUnsignedInteger() ? Fortran::common::TypeCategory::Unsigned
165 : Fortran::common::TypeCategory::Integer,
166 8};
167 else if (type.isInteger(128))
168 return {type.isUnsignedInteger() ? Fortran::common::TypeCategory::Unsigned
169 : Fortran::common::TypeCategory::Integer,
170 16};
171 else if (auto logicalType = mlir::dyn_cast<fir::LogicalType>(type))
172 return {Fortran::common::TypeCategory::Logical, logicalType.getFKind()};
173 else if (auto charType = mlir::dyn_cast<fir::CharacterType>(type))
174 return {Fortran::common::TypeCategory::Character, charType.getFKind()};
175 else if (mlir::isa<fir::RecordType>(type))
176 return {Fortran::common::TypeCategory::Derived, 0};
177 fir::emitFatalError(loc, "unsupported type: " + fir::mlirTypeToString(type));
178}
179
184fir::TypeInfoOp
185lookupTypeInfoOp(fir::RecordType recordType, mlir::ModuleOp module,
186 const mlir::SymbolTable *symbolTable = nullptr);
187
192fir::TypeInfoOp
193lookupTypeInfoOp(llvm::StringRef name, mlir::ModuleOp module,
194 const mlir::SymbolTable *symbolTable = nullptr);
195
199std::optional<llvm::ArrayRef<int64_t>> getComponentLowerBoundsIfNonDefault(
200 fir::RecordType recordType, llvm::StringRef component,
201 mlir::ModuleOp module, const mlir::SymbolTable *symbolTable = nullptr);
202
204mlir::LLVM::ConstantOp
205genConstantIndex(mlir::Location loc, mlir::Type ity,
206 mlir::ConversionPatternRewriter &rewriter,
207 std::int64_t offset);
208
213mlir::Value computeElementDistance(mlir::Location loc,
214 mlir::Type llvmObjectType, mlir::Type idxTy,
215 mlir::ConversionPatternRewriter &rewriter,
216 const mlir::DataLayout &dataLayout);
217
218// Compute the alloc scale size (constant factors encoded in the array type).
219// We do this for arrays without a constant interior or arrays of character with
220// dynamic length arrays, since those are the only ones that get decayed to a
221// pointer to the element type.
222mlir::Value genAllocationScaleSize(mlir::Location loc, mlir::Type dataTy,
223 mlir::Type ity,
224 mlir::ConversionPatternRewriter &rewriter);
225
230mlir::Value integerCast(const fir::LLVMTypeConverter &converter,
231 mlir::Location loc,
232 mlir::ConversionPatternRewriter &rewriter,
233 mlir::Type ty, mlir::Value val, bool fold = false);
234} // namespace fir
235
236#endif // FORTRAN_OPTIMIZER_SUPPORT_UTILS_H
Definition: default-kinds.h:26
Definition: FIRBuilder.h:55
Definition: TypeConverter.h:50
Definition: AbstractConverter.h:34
mlir::Value integerCast(const fir::LLVMTypeConverter &converter, mlir::Location loc, mlir::ConversionPatternRewriter &rewriter, mlir::Type ty, mlir::Value val, bool fold=false)
Definition: Utils.cpp:100
std::optional< llvm::ArrayRef< int64_t > > getComponentLowerBoundsIfNonDefault(fir::RecordType recordType, llvm::StringRef component, mlir::ModuleOp module, const mlir::SymbolTable *symbolTable=nullptr)
Definition: Utils.cpp:40
std::int64_t toInt(mlir::arith::ConstantOp cop)
Return the integer value of a arith::ConstantOp.
Definition: Utils.h:34
fir::TypeInfoOp lookupTypeInfoOp(fir::RecordType recordType, mlir::ModuleOp module, const mlir::SymbolTable *symbolTable=nullptr)
Definition: Utils.cpp:18
mlir::LLVM::ConstantOp genConstantIndex(mlir::Location loc, mlir::Type ity, mlir::ConversionPatternRewriter &rewriter, std::int64_t offset)
Generate a LLVM constant value of type ity, using the provided offset.
Definition: Utils.cpp:55
void emitFatalError(mlir::Location loc, const llvm::Twine &message, bool genCrashDiag=true)
Definition: FatalError.h:25
mlir::Value computeElementDistance(mlir::Location loc, mlir::Type llvmObjectType, mlir::Type idxTy, mlir::ConversionPatternRewriter &rewriter, const mlir::DataLayout &dataLayout)
Definition: Utils.cpp:63