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/Todo.h"
17#include "flang/Optimizer/Dialect/CUF/Attributes/CUFAttr.h"
18#include "flang/Optimizer/Dialect/FIROps.h"
19#include "flang/Optimizer/Dialect/FIRType.h"
20#include "flang/Optimizer/Support/FatalError.h"
21#include "flang/Support/default-kinds.h"
22#include "mlir/Dialect/Arith/IR/Arith.h"
23#include "mlir/Dialect/Func/IR/FuncOps.h"
24#include "mlir/Dialect/LLVMIR/LLVMAttrs.h"
25#include "mlir/IR/BuiltinAttributes.h"
26#include "mlir/IR/BuiltinOps.h"
27#include "mlir/IR/Location.h"
28#include "mlir/Interfaces/FunctionInterfaces.h"
29#include "llvm/ADT/StringRef.h"
30#include "llvm/Support/Path.h"
31#include <string>
32
33#include "flang/Optimizer/CodeGen/TypeConverter.h"
34
35namespace fir {
39inline uint32_t getLineFromLoc(mlir::Location loc) {
40 uint32_t line = 1;
41 if (auto fileLoc = loc->findInstanceOf<mlir::FileLineColLoc>())
42 line = fileLoc.getLine();
43 return line;
44}
45
47inline mlir::LLVM::DIFileAttr
48getFileAttrFromLoc(mlir::Location loc, mlir::LLVM::DIFileAttr fallback) {
49 auto fileLoc = loc->findInstanceOf<mlir::FileLineColLoc>();
50 if (!fileLoc)
51 return fallback;
52 llvm::StringRef path = fileLoc.getFilename().getValue();
53 return mlir::LLVM::DIFileAttr::get(loc.getContext(),
54 llvm::sys::path::filename(path),
55 llvm::sys::path::parent_path(path));
56}
57
59inline std::int64_t toInt(mlir::arith::ConstantOp cop) {
60 return mlir::cast<mlir::IntegerAttr>(cop.getValue())
61 .getValue()
62 .getSExtValue();
63}
64
65// Translate front-end KINDs for use in the IR and code gen.
66inline std::vector<fir::KindTy>
67fromDefaultKinds(const Fortran::common::IntrinsicTypeDefaultKinds &defKinds) {
68 return {static_cast<fir::KindTy>(defKinds.GetDefaultKind(
69 Fortran::common::TypeCategory::Character)),
70 static_cast<fir::KindTy>(
71 defKinds.GetDefaultKind(Fortran::common::TypeCategory::Complex)),
72 static_cast<fir::KindTy>(defKinds.doublePrecisionKind()),
73 static_cast<fir::KindTy>(
74 defKinds.GetDefaultKind(Fortran::common::TypeCategory::Integer)),
75 static_cast<fir::KindTy>(
76 defKinds.GetDefaultKind(Fortran::common::TypeCategory::Logical)),
77 static_cast<fir::KindTy>(
78 defKinds.GetDefaultKind(Fortran::common::TypeCategory::Real))};
79}
80
81inline std::string mlirTypeToString(mlir::Type type) {
82 std::string result{};
83 llvm::raw_string_ostream sstream(result);
84 sstream << type;
85 return result;
86}
87
88inline std::optional<int> mlirFloatTypeToKind(mlir::Type type) {
89 if (type.isF16())
90 return 2;
91 else if (type.isBF16())
92 return 3;
93 else if (type.isF32())
94 return 4;
95 else if (type.isF64())
96 return 8;
97 else if (type.isF80())
98 return 10;
99 else if (type.isF128())
100 return 16;
101 return std::nullopt;
102}
103
104inline std::string mlirTypeToIntrinsicFortran(mlir::Type type,
105 mlir::Location loc,
106 const llvm::Twine &name) {
107 if (auto floatTy = mlir::dyn_cast<mlir::FloatType>(type)) {
108 if (std::optional<int> kind = mlirFloatTypeToKind(type))
109 return "REAL(KIND=" + std::to_string(*kind) + ")";
110 } else if (auto cplxTy = mlir::dyn_cast<mlir::ComplexType>(type)) {
111 if (std::optional<int> kind = mlirFloatTypeToKind(cplxTy.getElementType()))
112 return "COMPLEX(KIND=" + std::to_string(*kind) + ")";
113 } else if (type.isUnsignedInteger()) {
114 if (type.isInteger(8))
115 return "UNSIGNED(KIND=1)";
116 else if (type.isInteger(16))
117 return "UNSIGNED(KIND=2)";
118 else if (type.isInteger(32))
119 return "UNSIGNED(KIND=4)";
120 else if (type.isInteger(64))
121 return "UNSIGNED(KIND=8)";
122 else if (type.isInteger(128))
123 return "UNSIGNED(KIND=16)";
124 } else if (type.isInteger(8))
125 return "INTEGER(KIND=1)";
126 else if (type.isInteger(16))
127 return "INTEGER(KIND=2)";
128 else if (type.isInteger(32))
129 return "INTEGER(KIND=4)";
130 else if (type.isInteger(64))
131 return "INTEGER(KIND=8)";
132 else if (type.isInteger(128))
133 return "INTEGER(KIND=16)";
134 else if (type == fir::LogicalType::get(type.getContext(), 1))
135 return "LOGICAL(KIND=1)";
136 else if (type == fir::LogicalType::get(type.getContext(), 2))
137 return "LOGICAL(KIND=2)";
138 else if (type == fir::LogicalType::get(type.getContext(), 4))
139 return "LOGICAL(KIND=4)";
140 else if (type == fir::LogicalType::get(type.getContext(), 8))
141 return "LOGICAL(KIND=8)";
142
143 fir::emitFatalError(loc, "unsupported type in " + name + ": " +
144 fir::mlirTypeToString(type));
145}
146
147inline void intrinsicTypeTODO(mlir::Type type, mlir::Location loc,
148 const llvm::Twine &intrinsicName) {
149 TODO(loc, "intrinsic: " +
150 fir::mlirTypeToIntrinsicFortran(type, loc, intrinsicName) +
151 " in " + intrinsicName);
152}
153
154inline void intrinsicTypeTODO2(mlir::Type type1, mlir::Type type2,
155 mlir::Location loc,
156 const llvm::Twine &intrinsicName) {
157 TODO(loc, "intrinsic: {" +
158 fir::mlirTypeToIntrinsicFortran(type1, loc, intrinsicName) +
159 ", " +
160 fir::mlirTypeToIntrinsicFortran(type2, loc, intrinsicName) +
161 "} in " + intrinsicName);
162}
163
164inline std::pair<Fortran::common::TypeCategory, KindMapping::KindTy>
165mlirTypeToCategoryKind(mlir::Location loc, mlir::Type type) {
166 if (auto floatTy = mlir::dyn_cast<mlir::FloatType>(type)) {
167 if (std::optional<int> kind = mlirFloatTypeToKind(type))
168 return {Fortran::common::TypeCategory::Real, *kind};
169 } else if (auto cplxTy = mlir::dyn_cast<mlir::ComplexType>(type)) {
170 if (std::optional<int> kind = mlirFloatTypeToKind(cplxTy.getElementType()))
171 return {Fortran::common::TypeCategory::Complex, *kind};
172 } else if (type.isInteger(8))
173 return {type.isUnsignedInteger() ? Fortran::common::TypeCategory::Unsigned
174 : Fortran::common::TypeCategory::Integer,
175 1};
176 else if (type.isInteger(16))
177 return {type.isUnsignedInteger() ? Fortran::common::TypeCategory::Unsigned
178 : Fortran::common::TypeCategory::Integer,
179 2};
180 else if (type.isInteger(32))
181 return {type.isUnsignedInteger() ? Fortran::common::TypeCategory::Unsigned
182 : Fortran::common::TypeCategory::Integer,
183 4};
184 else if (type.isInteger(64))
185 return {type.isUnsignedInteger() ? Fortran::common::TypeCategory::Unsigned
186 : Fortran::common::TypeCategory::Integer,
187 8};
188 else if (type.isInteger(128))
189 return {type.isUnsignedInteger() ? Fortran::common::TypeCategory::Unsigned
190 : Fortran::common::TypeCategory::Integer,
191 16};
192 else if (auto logicalType = mlir::dyn_cast<fir::LogicalType>(type))
193 return {Fortran::common::TypeCategory::Logical, logicalType.getFKind()};
194 else if (auto charType = mlir::dyn_cast<fir::CharacterType>(type))
195 return {Fortran::common::TypeCategory::Character, charType.getFKind()};
196 else if (mlir::isa<fir::RecordType>(type))
197 return {Fortran::common::TypeCategory::Derived, 0};
198 fir::emitFatalError(loc, "unsupported type: " + fir::mlirTypeToString(type));
199}
200
205fir::TypeInfoOp
206lookupTypeInfoOp(fir::RecordType recordType, mlir::ModuleOp module,
207 const mlir::SymbolTable *symbolTable = nullptr);
208
213fir::TypeInfoOp
214lookupTypeInfoOp(llvm::StringRef name, mlir::ModuleOp module,
215 const mlir::SymbolTable *symbolTable = nullptr);
216
220std::optional<llvm::ArrayRef<int64_t>> getComponentLowerBoundsIfNonDefault(
221 fir::RecordType recordType, llvm::StringRef component,
222 mlir::ModuleOp module, const mlir::SymbolTable *symbolTable = nullptr);
223
226std::optional<bool>
227isRecordWithFinalRoutine(fir::RecordType recordType, mlir::ModuleOp module,
228 const mlir::SymbolTable *symbolTable = nullptr);
229
231mlir::LLVM::ConstantOp
232genConstantIndex(mlir::Location loc, mlir::Type ity,
233 mlir::ConversionPatternRewriter &rewriter,
234 std::int64_t offset);
235
240mlir::Value computeElementDistance(mlir::Location loc,
241 mlir::Type llvmObjectType, mlir::Type idxTy,
242 mlir::ConversionPatternRewriter &rewriter,
243 const mlir::DataLayout &dataLayout);
244
245// Compute the alloc scale size (constant factors encoded in the array type).
246// We do this for arrays without a constant interior or arrays of character with
247// dynamic length arrays, since those are the only ones that get decayed to a
248// pointer to the element type.
249mlir::Value genAllocationScaleSize(mlir::Location loc, mlir::Type dataTy,
250 mlir::Type ity,
251 mlir::ConversionPatternRewriter &rewriter);
252
257mlir::Value integerCast(const fir::LLVMTypeConverter &converter,
258 mlir::Location loc,
259 mlir::ConversionPatternRewriter &rewriter,
260 mlir::Type ty, mlir::Value val, bool fold = false);
261
267std::optional<bool> isNewAllocationResult(mlir::OpResult result);
268
272mlir::FunctionOpInterface getPresentedFunction(mlir::FunctionOpInterface func);
273
276mlir::FunctionOpInterface getPresentedCallee(mlir::Operation *call,
277 mlir::SymbolRefAttr callee);
278
282std::string getPresentableFunctionName(mlir::FunctionOpInterface func);
283} // namespace fir
284
285#endif // FORTRAN_OPTIMIZER_SUPPORT_UTILS_H
Definition default-kinds.h:26
Definition AbstractConverter.h:37
uint32_t getLineFromLoc(mlir::Location loc)
Definition Utils.h:39
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:111
std::string getPresentableFunctionName(mlir::FunctionOpInterface func)
Definition Utils.cpp:175
std::optional< bool > isNewAllocationResult(mlir::OpResult result)
Definition Utils.cpp:136
std::optional< bool > isRecordWithFinalRoutine(fir::RecordType recordType, mlir::ModuleOp module, const mlir::SymbolTable *symbolTable=nullptr)
Definition Utils.cpp:56
std::optional< llvm::ArrayRef< int64_t > > getComponentLowerBoundsIfNonDefault(fir::RecordType recordType, llvm::StringRef component, mlir::ModuleOp module, const mlir::SymbolTable *symbolTable=nullptr)
Definition Utils.cpp:41
mlir::FunctionOpInterface getPresentedFunction(mlir::FunctionOpInterface func)
Definition Utils.cpp:154
std::int64_t toInt(mlir::arith::ConstantOp cop)
Return the integer value of a arith::ConstantOp.
Definition Utils.h:59
fir::TypeInfoOp lookupTypeInfoOp(fir::RecordType recordType, mlir::ModuleOp module, const mlir::SymbolTable *symbolTable=nullptr)
Definition Utils.cpp:19
mlir::FunctionOpInterface getPresentedCallee(mlir::Operation *call, mlir::SymbolRefAttr callee)
Definition Utils.cpp:165
mlir::LLVM::DIFileAttr getFileAttrFromLoc(mlir::Location loc, mlir::LLVM::DIFileAttr fallback)
Return the file that loc names, or fallback if it names none.
Definition Utils.h:48
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:66
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:74