FLANG
FIROpPatterns.h
1//===-- FIROpPatterns.h -- FIR operation conversion patterns ----*- 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#ifndef FORTRAN_OPTIMIZER_CODEGEN_FIROPPATTERNS_H
10#define FORTRAN_OPTIMIZER_CODEGEN_FIROPPATTERNS_H
11
12#include "flang/Optimizer/CodeGen/TypeConverter.h"
13#include "mlir/Conversion/LLVMCommon/Pattern.h"
14#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
15#include "mlir/IR/SymbolTable.h"
16#include <type_traits>
17
18namespace fir {
19
21
22static constexpr unsigned defaultAddressSpace = 0u;
23
65
70template <typename OpTy, typename NameT>
71OpTy lookupSymbolIn(mlir::Operation *symbolTableOp, NameT name,
72 mlir::SymbolTableCollection *symbolTables) {
73 if (!symbolTables)
74 return mlir::dyn_cast_or_null<OpTy>(
75 mlir::SymbolTable::lookupSymbolIn(symbolTableOp, name));
76 OpTy op;
77 if constexpr (std::is_same_v<NameT, mlir::SymbolRefAttr>)
78 op = symbolTables->lookupSymbolIn<OpTy>(symbolTableOp, name);
79 else
80 op = symbolTables->getSymbolTable(symbolTableOp).lookup<OpTy>(name);
81#ifdef EXPENSIVE_CHECKS
82 // A replacement is always inserted before the operation it replaces, so on
83 // a hit the linear walk must find the same operation.
84 assert((!op ||
85 op == mlir::dyn_cast_or_null<OpTy>(
86 mlir::SymbolTable::lookupSymbolIn(symbolTableOp, name))) &&
87 "symbol tables and module out of sync");
88#endif
89 return op;
90}
91
94void registerSymbol(mlir::SymbolTableCollection *symbolTables,
95 mlir::Operation *symbolTableOp, mlir::Operation *symbol);
96
100void replaceSymbol(mlir::SymbolTableCollection *symbolTables,
101 mlir::Operation *symbolTableOp, mlir::Operation *oldSymbol,
102 mlir::Operation *newSymbol);
103
105void unregisterSymbol(mlir::SymbolTableCollection *symbolTables,
106 mlir::Operation *symbolTableOp, mlir::Operation *symbol);
107
113void buildSymbolTables(mlir::SymbolTableCollection &symbolTables,
114 mlir::Operation *root);
115
116class ConvertFIRToLLVMPattern : public mlir::ConvertToLLVMPattern {
117public:
118 ConvertFIRToLLVMPattern(llvm::StringRef rootOpName,
119 mlir::MLIRContext *context,
120 const fir::LLVMTypeConverter &typeConverter,
121 const fir::FIRToLLVMPassOptions &options,
122 mlir::SymbolTableCollection *symbolTables = nullptr,
123 mlir::PatternBenefit benefit = 1);
124
125protected:
126 mlir::Type convertType(mlir::Type ty) const {
127 return lowerTy().convertType(ty);
128 }
129
130 // Convert FIR type to LLVM without turning fir.box<T> into memory
131 // reference.
132 mlir::Type convertObjectType(mlir::Type firType) const;
133
134 mlir::LLVM::ConstantOp
135 genI32Constant(mlir::Location loc, mlir::ConversionPatternRewriter &rewriter,
136 int value) const;
137
138 mlir::LLVM::ConstantOp
139 genConstantOffset(mlir::Location loc,
140 mlir::ConversionPatternRewriter &rewriter,
141 int offset) const;
142
147 mlir::Value integerCast(mlir::Location loc,
148 mlir::ConversionPatternRewriter &rewriter,
149 mlir::Type ty, mlir::Value val,
150 bool fold = false) const;
151
152 struct TypePair {
153 mlir::Type fir;
154 mlir::Type llvm;
155 };
156
157 TypePair getBoxTypePair(mlir::Type firBoxTy) const;
158
160 mlir::Value getValueFromBox(mlir::Location loc, TypePair boxTy,
161 mlir::Value box, mlir::Type resultTy,
162 mlir::ConversionPatternRewriter &rewriter,
163 int boxValue) const;
164
168 getDimsFromBox(mlir::Location loc, llvm::ArrayRef<mlir::Type> retTys,
169 TypePair boxTy, mlir::Value box, mlir::Value dim,
170 mlir::ConversionPatternRewriter &rewriter) const;
171
173 getDimsFromBox(mlir::Location loc, llvm::ArrayRef<mlir::Type> retTys,
174 TypePair boxTy, mlir::Value box, int dim,
175 mlir::ConversionPatternRewriter &rewriter) const;
176
177 mlir::Value
178 loadDimFieldFromBox(mlir::Location loc, TypePair boxTy, mlir::Value box,
179 mlir::Value dim, int off, mlir::Type ty,
180 mlir::ConversionPatternRewriter &rewriter) const;
181
182 mlir::Value
183 getDimFieldFromBox(mlir::Location loc, TypePair boxTy, mlir::Value box,
184 int dim, int off, mlir::Type ty,
185 mlir::ConversionPatternRewriter &rewriter) const;
186
187 mlir::Value getStrideFromBox(mlir::Location loc, TypePair boxTy,
188 mlir::Value box, unsigned dim,
189 mlir::ConversionPatternRewriter &rewriter) const;
190
192 mlir::Value
193 getBaseAddrFromBox(mlir::Location loc, TypePair boxTy, mlir::Value box,
194 mlir::ConversionPatternRewriter &rewriter) const;
195
196 mlir::Value
197 getElementSizeFromBox(mlir::Location loc, mlir::Type resultTy, TypePair boxTy,
198 mlir::Value box,
199 mlir::ConversionPatternRewriter &rewriter) const;
200
201 mlir::Value getRankFromBox(mlir::Location loc, TypePair boxTy,
202 mlir::Value box,
203 mlir::ConversionPatternRewriter &rewriter) const;
204
205 mlir::Value getExtraFromBox(mlir::Location loc, TypePair boxTy,
206 mlir::Value box,
207 mlir::ConversionPatternRewriter &rewriter) const;
208
209 // Get the element type given an LLVM type that is of the form
210 // (array|struct|vector)+ and the provided indexes.
211 mlir::Type getBoxEleTy(mlir::Type type,
212 llvm::ArrayRef<std::int64_t> indexes) const;
213
214 // Return LLVM type of the object described by a fir.box of \p boxType.
215 mlir::Type getLlvmObjectTypeFromBoxType(mlir::Type boxType) const;
216
218 mlir::Value
219 loadTypeDescAddress(mlir::Location loc, TypePair boxTy, mlir::Value box,
220 mlir::ConversionPatternRewriter &rewriter) const;
221
222 // Load the attribute from the \p box and perform a check against \p maskValue
223 // The final comparison is implemented as `(attribute & maskValue) != 0`.
224 mlir::Value genBoxAttributeCheck(mlir::Location loc, TypePair boxTy,
225 mlir::Value box,
226 mlir::ConversionPatternRewriter &rewriter,
227 unsigned maskValue) const;
228
232 mlir::Value computeBoxSize(mlir::Location, TypePair boxTy, mlir::Value box,
233 mlir::ConversionPatternRewriter &rewriter) const;
234
235 template <typename... ARGS>
236 mlir::LLVM::GEPOp genGEP(mlir::Location loc, mlir::Type ty,
237 mlir::ConversionPatternRewriter &rewriter,
238 mlir::Value base, ARGS... args) const {
240 auto llvmPtrTy =
241 mlir::LLVM::LLVMPointerType::get(ty.getContext(), /*addressSpace=*/0);
242 return mlir::LLVM::GEPOp::create(rewriter, loc, llvmPtrTy, ty, base, cv);
243 }
244
245 // Find the Block in which the alloca should be inserted.
246 // The order to recursively find the proper block:
247 // 1. An OpenMP Op that will be outlined.
248 // 2. An OpenMP or OpenACC Op with one or more regions holding executable
249 // code.
250 // 3. A LLVMFuncOp
251 // 4. The first ancestor that is one of the above.
252 mlir::Block *getBlockForAllocaInsert(mlir::Operation *op,
253 mlir::Region *parentRegion) const;
254
255 // Generate an alloca of size 1 for an object of type \p llvmObjectTy in the
256 // allocation address space provided for the architecture in the DataLayout
257 // specification. If the address space is different from the devices
258 // program address space we perform a cast. In the case of most architectures
259 // the program and allocation address space will be the default of 0 and no
260 // cast will be emitted.
261 mlir::Value
262 genAllocaAndAddrCastWithType(mlir::Location loc, mlir::Type llvmObjectTy,
263 unsigned alignment,
264 mlir::ConversionPatternRewriter &rewriter) const;
265
266 const fir::LLVMTypeConverter &lowerTy() const {
267 return *static_cast<const fir::LLVMTypeConverter *>(
268 this->getTypeConverter());
269 }
270
271 const mlir::DataLayout &getDataLayout() const {
272 return lowerTy().getDataLayout();
273 }
274
275 void attachTBAATag(mlir::LLVM::AliasAnalysisOpInterface op,
276 mlir::Type baseFIRType, mlir::Type accessFIRType,
277 mlir::LLVM::GEPOp gep) const {
278 lowerTy().attachTBAATag(op, baseFIRType, accessFIRType, gep);
279 }
280
281 unsigned
282 getAllocaAddressSpace(mlir::ConversionPatternRewriter &rewriter) const;
283
284 unsigned
285 getProgramAddressSpace(mlir::ConversionPatternRewriter &rewriter) const;
286
287 unsigned
288 getGlobalAddressSpace(mlir::ConversionPatternRewriter &rewriter) const;
289
290 const fir::FIRToLLVMPassOptions &options;
291
295 mlir::SymbolTableCollection *symbolTables;
296
297 using ConvertToLLVMPattern::matchAndRewrite;
298};
299
300template <typename SourceOp>
301class FIROpConversion : public ConvertFIRToLLVMPattern {
302public:
303 using OpAdaptor = typename SourceOp::Adaptor;
304 using OneToNOpAdaptor = typename SourceOp::template GenericAdaptor<
305 mlir::ArrayRef<mlir::ValueRange>>;
306
307 explicit FIROpConversion(const LLVMTypeConverter &typeConverter,
308 const fir::FIRToLLVMPassOptions &options,
309 mlir::SymbolTableCollection *symbolTables = nullptr,
310 mlir::PatternBenefit benefit = 1)
311 : ConvertFIRToLLVMPattern(SourceOp::getOperationName(),
312 &typeConverter.getContext(), typeConverter,
313 options, symbolTables, benefit) {}
314
316 llvm::LogicalResult
317 matchAndRewrite(mlir::Operation *op, mlir::ArrayRef<mlir::Value> operands,
318 mlir::ConversionPatternRewriter &rewriter) const final {
319 return matchAndRewrite(mlir::cast<SourceOp>(op),
320 OpAdaptor(operands, mlir::cast<SourceOp>(op)),
321 rewriter);
322 }
323 llvm::LogicalResult
324 matchAndRewrite(mlir::Operation *op,
325 mlir::ArrayRef<mlir::ValueRange> operands,
326 mlir::ConversionPatternRewriter &rewriter) const final {
327 auto sourceOp = mlir::cast<SourceOp>(op);
328 return matchAndRewrite(sourceOp, OneToNOpAdaptor(operands, sourceOp),
329 rewriter);
330 }
333 virtual llvm::LogicalResult
334 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
335 mlir::ConversionPatternRewriter &rewriter) const {
336 llvm_unreachable("matchAndRewrite is not implemented");
337 }
338 virtual llvm::LogicalResult
339 matchAndRewrite(SourceOp op, OneToNOpAdaptor adaptor,
340 mlir::ConversionPatternRewriter &rewriter) const {
341 return dispatchTo1To1(*this, op, adaptor, rewriter);
342 }
343
344private:
345 using ConvertFIRToLLVMPattern::matchAndRewrite;
346};
347
349template <typename FromOp>
350class FIROpAndTypeConversion : public FIROpConversion<FromOp> {
351public:
352 using FIROpConversion<FromOp>::FIROpConversion;
353 using OpAdaptor = typename FromOp::Adaptor;
354
355 llvm::LogicalResult
356 matchAndRewrite(FromOp op, OpAdaptor adaptor,
357 mlir::ConversionPatternRewriter &rewriter) const final {
358 mlir::Type ty = this->convertType(op.getType());
359 return doRewrite(op, ty, adaptor, rewriter);
360 }
361
362 virtual llvm::LogicalResult
363 doRewrite(FromOp addr, mlir::Type ty, OpAdaptor adaptor,
364 mlir::ConversionPatternRewriter &rewriter) const = 0;
365};
366
367} // namespace fir
368
369#endif // FORTRAN_OPTIMIZER_CODEGEN_FIROPPATTERNS_H
llvm::SmallVector< mlir::Value, 3 > getDimsFromBox(mlir::Location loc, llvm::ArrayRef< mlir::Type > retTys, TypePair boxTy, mlir::Value box, mlir::Value dim, mlir::ConversionPatternRewriter &rewriter) const
Definition FIROpPatterns.cpp:155
mlir::Value computeBoxSize(mlir::Location, TypePair boxTy, mlir::Value box, mlir::ConversionPatternRewriter &rewriter) const
Definition FIROpPatterns.cpp:299
mlir::SymbolTableCollection * symbolTables
Definition FIROpPatterns.h:295
mlir::Value getRankFromBox(mlir::Location loc, TypePair boxTy, mlir::Value box, mlir::ConversionPatternRewriter &rewriter) const
Read base address from a fir.box. Returned address has type ty.
Definition FIROpPatterns.cpp:231
mlir::Value getBaseAddrFromBox(mlir::Location loc, TypePair boxTy, mlir::Value box, mlir::ConversionPatternRewriter &rewriter) const
Read base address from a fir.box. Returned address has type ty.
Definition FIROpPatterns.cpp:217
mlir::Value integerCast(mlir::Location loc, mlir::ConversionPatternRewriter &rewriter, mlir::Type ty, mlir::Value val, bool fold=false) const
Definition FIROpPatterns.cpp:104
mlir::Value getExtraFromBox(mlir::Location loc, TypePair boxTy, mlir::Value box, mlir::ConversionPatternRewriter &rewriter) const
Read the extra field from a fir.box.
Definition FIROpPatterns.cpp:239
mlir::Value loadTypeDescAddress(mlir::Location loc, TypePair boxTy, mlir::Value box, mlir::ConversionPatternRewriter &rewriter) const
Read the address of the type descriptor from a box.
Definition FIROpPatterns.cpp:275
mlir::Value getValueFromBox(mlir::Location loc, TypePair boxTy, mlir::Value box, mlir::Type resultTy, mlir::ConversionPatternRewriter &rewriter, int boxValue) const
Construct code sequence to extract the specific value from a fir.box.
Definition FIROpPatterns.cpp:136
FIR conversion pattern template.
Definition FIROpPatterns.h:350
virtual llvm::LogicalResult matchAndRewrite(SourceOp op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const
Definition FIROpPatterns.h:334
llvm::LogicalResult matchAndRewrite(mlir::Operation *op, mlir::ArrayRef< mlir::Value > operands, mlir::ConversionPatternRewriter &rewriter) const final
Wrappers around the RewritePattern methods that pass the derived op type.
Definition FIROpPatterns.h:317
Definition TypeConverter.h:49
Definition FIRType.h:106
Definition OpenACC.h:20
Definition AbstractConverter.h:37
void buildSymbolTables(mlir::SymbolTableCollection &symbolTables, mlir::Operation *root)
Definition FIROpPatterns.cpp:67
void replaceSymbol(mlir::SymbolTableCollection *symbolTables, mlir::Operation *symbolTableOp, mlir::Operation *oldSymbol, mlir::Operation *newSymbol)
Definition FIROpPatterns.cpp:52
OpTy lookupSymbolIn(mlir::Operation *symbolTableOp, NameT name, mlir::SymbolTableCollection *symbolTables)
Definition FIROpPatterns.h:71
void registerSymbol(mlir::SymbolTableCollection *symbolTables, mlir::Operation *symbolTableOp, mlir::Operation *symbol)
Definition FIROpPatterns.cpp:37
void unregisterSymbol(mlir::SymbolTableCollection *symbolTables, mlir::Operation *symbolTableOp, mlir::Operation *symbol)
Forget symbol, which is about to be erased. No-op without a collection.
Definition FIROpPatterns.cpp:61
Definition FIROpPatterns.h:152
FIR to LLVM translation pass options.
Definition CodeGen.h:40