Skip to content

Commit e9639e9

Browse files
authored
[flang][NFC] Extract FIROpConversion to its own files (#86213)
This PR extracts `FIROpConversion` and `FIROpAndTypeConversion` templated base patterns to a header file. All the functions from FIROpConversion that do not require the template argument are moved to a base class named `ConvertFIRToLLVMPattern`. This move is done so the `FIROpConversion` pattern and all its utility functions can be reused outside of the codegen pass. For the most part the code is only moved to the new files and not modified. The only update is that addition of the PatternBenefit argument with a default value to the constructor so it can be forwarded to the `ConversionPattern` ctor. This split is done in a similar way for the `ConvertOpToLLVMPattern` base pattern that is based on the `ConvertToLLVMPattern` base class in `mlir/include/mlir/Conversion/LLVMCommon/Pattern.h`.
1 parent dfe4ca9 commit e9639e9

File tree

5 files changed

+636
-418
lines changed

5 files changed

+636
-418
lines changed
Lines changed: 248 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,248 @@
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+
16+
namespace fir {
17+
18+
struct FIRToLLVMPassOptions;
19+
20+
static constexpr unsigned defaultAddressSpace = 0u;
21+
22+
class ConvertFIRToLLVMPattern : public mlir::ConvertToLLVMPattern {
23+
public:
24+
ConvertFIRToLLVMPattern(llvm::StringRef rootOpName,
25+
mlir::MLIRContext *context,
26+
const fir::LLVMTypeConverter &typeConverter,
27+
const fir::FIRToLLVMPassOptions &options,
28+
mlir::PatternBenefit benefit = 1);
29+
30+
protected:
31+
mlir::Type convertType(mlir::Type ty) const {
32+
return lowerTy().convertType(ty);
33+
}
34+
35+
// Convert FIR type to LLVM without turning fir.box<T> into memory
36+
// reference.
37+
mlir::Type convertObjectType(mlir::Type firType) const;
38+
39+
mlir::LLVM::ConstantOp
40+
genI32Constant(mlir::Location loc, mlir::ConversionPatternRewriter &rewriter,
41+
int value) const;
42+
43+
mlir::LLVM::ConstantOp
44+
genConstantOffset(mlir::Location loc,
45+
mlir::ConversionPatternRewriter &rewriter,
46+
int offset) const;
47+
48+
/// Perform an extension or truncation as needed on an integer value. Lowering
49+
/// to the specific target may involve some sign-extending or truncation of
50+
/// values, particularly to fit them from abstract box types to the
51+
/// appropriate reified structures.
52+
mlir::Value integerCast(mlir::Location loc,
53+
mlir::ConversionPatternRewriter &rewriter,
54+
mlir::Type ty, mlir::Value val) const;
55+
struct TypePair {
56+
mlir::Type fir;
57+
mlir::Type llvm;
58+
};
59+
60+
TypePair getBoxTypePair(mlir::Type firBoxTy) const;
61+
62+
/// Construct code sequence to extract the specific value from a `fir.box`.
63+
mlir::Value getValueFromBox(mlir::Location loc, TypePair boxTy,
64+
mlir::Value box, mlir::Type resultTy,
65+
mlir::ConversionPatternRewriter &rewriter,
66+
int boxValue) const;
67+
68+
/// Method to construct code sequence to get the triple for dimension `dim`
69+
/// from a box.
70+
llvm::SmallVector<mlir::Value, 3>
71+
getDimsFromBox(mlir::Location loc, llvm::ArrayRef<mlir::Type> retTys,
72+
TypePair boxTy, mlir::Value box, mlir::Value dim,
73+
mlir::ConversionPatternRewriter &rewriter) const;
74+
75+
llvm::SmallVector<mlir::Value, 3>
76+
getDimsFromBox(mlir::Location loc, llvm::ArrayRef<mlir::Type> retTys,
77+
TypePair boxTy, mlir::Value box, int dim,
78+
mlir::ConversionPatternRewriter &rewriter) const;
79+
80+
mlir::Value
81+
loadDimFieldFromBox(mlir::Location loc, TypePair boxTy, mlir::Value box,
82+
mlir::Value dim, int off, mlir::Type ty,
83+
mlir::ConversionPatternRewriter &rewriter) const;
84+
85+
mlir::Value
86+
getDimFieldFromBox(mlir::Location loc, TypePair boxTy, mlir::Value box,
87+
int dim, int off, mlir::Type ty,
88+
mlir::ConversionPatternRewriter &rewriter) const;
89+
90+
mlir::Value getStrideFromBox(mlir::Location loc, TypePair boxTy,
91+
mlir::Value box, unsigned dim,
92+
mlir::ConversionPatternRewriter &rewriter) const;
93+
94+
/// Read base address from a fir.box. Returned address has type ty.
95+
mlir::Value
96+
getBaseAddrFromBox(mlir::Location loc, TypePair boxTy, mlir::Value box,
97+
mlir::ConversionPatternRewriter &rewriter) const;
98+
99+
mlir::Value
100+
getElementSizeFromBox(mlir::Location loc, mlir::Type resultTy, TypePair boxTy,
101+
mlir::Value box,
102+
mlir::ConversionPatternRewriter &rewriter) const;
103+
104+
// Get the element type given an LLVM type that is of the form
105+
// (array|struct|vector)+ and the provided indexes.
106+
mlir::Type getBoxEleTy(mlir::Type type,
107+
llvm::ArrayRef<std::int64_t> indexes) const;
108+
109+
// Return LLVM type of the object described by a fir.box of \p boxType.
110+
mlir::Type getLlvmObjectTypeFromBoxType(mlir::Type boxType) const;
111+
112+
/// Read the address of the type descriptor from a box.
113+
mlir::Value
114+
loadTypeDescAddress(mlir::Location loc, TypePair boxTy, mlir::Value box,
115+
mlir::ConversionPatternRewriter &rewriter) const;
116+
117+
// Load the attribute from the \p box and perform a check against \p maskValue
118+
// The final comparison is implemented as `(attribute & maskValue) != 0`.
119+
mlir::Value genBoxAttributeCheck(mlir::Location loc, TypePair boxTy,
120+
mlir::Value box,
121+
mlir::ConversionPatternRewriter &rewriter,
122+
unsigned maskValue) const;
123+
124+
template <typename... ARGS>
125+
mlir::LLVM::GEPOp genGEP(mlir::Location loc, mlir::Type ty,
126+
mlir::ConversionPatternRewriter &rewriter,
127+
mlir::Value base, ARGS... args) const {
128+
llvm::SmallVector<mlir::LLVM::GEPArg> cv = {args...};
129+
auto llvmPtrTy =
130+
mlir::LLVM::LLVMPointerType::get(ty.getContext(), /*addressSpace=*/0);
131+
return rewriter.create<mlir::LLVM::GEPOp>(loc, llvmPtrTy, ty, base, cv);
132+
}
133+
134+
// Find the Block in which the alloca should be inserted.
135+
// The order to recursively find the proper block:
136+
// 1. An OpenMP Op that will be outlined.
137+
// 2. A LLVMFuncOp
138+
// 3. The first ancestor that is an OpenMP Op or a LLVMFuncOp
139+
mlir::Block *getBlockForAllocaInsert(mlir::Operation *op) const;
140+
141+
// Generate an alloca of size 1 for an object of type \p llvmObjectTy in the
142+
// allocation address space provided for the architecture in the DataLayout
143+
// specification. If the address space is different from the devices
144+
// program address space we perform a cast. In the case of most architectures
145+
// the program and allocation address space will be the default of 0 and no
146+
// cast will be emitted.
147+
mlir::Value
148+
genAllocaAndAddrCastWithType(mlir::Location loc, mlir::Type llvmObjectTy,
149+
unsigned alignment,
150+
mlir::ConversionPatternRewriter &rewriter) const;
151+
152+
const fir::LLVMTypeConverter &lowerTy() const {
153+
return *static_cast<const fir::LLVMTypeConverter *>(
154+
this->getTypeConverter());
155+
}
156+
157+
void attachTBAATag(mlir::LLVM::AliasAnalysisOpInterface op,
158+
mlir::Type baseFIRType, mlir::Type accessFIRType,
159+
mlir::LLVM::GEPOp gep) const {
160+
lowerTy().attachTBAATag(op, baseFIRType, accessFIRType, gep);
161+
}
162+
163+
unsigned
164+
getAllocaAddressSpace(mlir::ConversionPatternRewriter &rewriter) const;
165+
166+
unsigned
167+
getProgramAddressSpace(mlir::ConversionPatternRewriter &rewriter) const;
168+
169+
const fir::FIRToLLVMPassOptions &options;
170+
171+
using ConvertToLLVMPattern::match;
172+
using ConvertToLLVMPattern::matchAndRewrite;
173+
};
174+
175+
template <typename SourceOp>
176+
class FIROpConversion : public ConvertFIRToLLVMPattern {
177+
public:
178+
using OpAdaptor = typename SourceOp::Adaptor;
179+
180+
explicit FIROpConversion(const LLVMTypeConverter &typeConverter,
181+
const fir::FIRToLLVMPassOptions &options,
182+
mlir::PatternBenefit benefit = 1)
183+
: ConvertFIRToLLVMPattern(SourceOp::getOperationName(),
184+
&typeConverter.getContext(), typeConverter,
185+
options, benefit) {}
186+
187+
/// Wrappers around the RewritePattern methods that pass the derived op type.
188+
void rewrite(mlir::Operation *op, mlir::ArrayRef<mlir::Value> operands,
189+
mlir::ConversionPatternRewriter &rewriter) const final {
190+
rewrite(mlir::cast<SourceOp>(op),
191+
OpAdaptor(operands, mlir::cast<SourceOp>(op)), rewriter);
192+
}
193+
mlir::LogicalResult match(mlir::Operation *op) const final {
194+
return match(mlir::cast<SourceOp>(op));
195+
}
196+
mlir::LogicalResult
197+
matchAndRewrite(mlir::Operation *op, mlir::ArrayRef<mlir::Value> operands,
198+
mlir::ConversionPatternRewriter &rewriter) const final {
199+
return matchAndRewrite(mlir::cast<SourceOp>(op),
200+
OpAdaptor(operands, mlir::cast<SourceOp>(op)),
201+
rewriter);
202+
}
203+
204+
/// Rewrite and Match methods that operate on the SourceOp type. These must be
205+
/// overridden by the derived pattern class.
206+
virtual mlir::LogicalResult match(SourceOp op) const {
207+
llvm_unreachable("must override match or matchAndRewrite");
208+
}
209+
virtual void rewrite(SourceOp op, OpAdaptor adaptor,
210+
mlir::ConversionPatternRewriter &rewriter) const {
211+
llvm_unreachable("must override rewrite or matchAndRewrite");
212+
}
213+
virtual mlir::LogicalResult
214+
matchAndRewrite(SourceOp op, OpAdaptor adaptor,
215+
mlir::ConversionPatternRewriter &rewriter) const {
216+
if (mlir::failed(match(op)))
217+
return mlir::failure();
218+
rewrite(op, adaptor, rewriter);
219+
return mlir::success();
220+
}
221+
222+
private:
223+
using ConvertFIRToLLVMPattern::matchAndRewrite;
224+
using ConvertToLLVMPattern::match;
225+
};
226+
227+
/// FIR conversion pattern template
228+
template <typename FromOp>
229+
class FIROpAndTypeConversion : public FIROpConversion<FromOp> {
230+
public:
231+
using FIROpConversion<FromOp>::FIROpConversion;
232+
using OpAdaptor = typename FromOp::Adaptor;
233+
234+
mlir::LogicalResult
235+
matchAndRewrite(FromOp op, OpAdaptor adaptor,
236+
mlir::ConversionPatternRewriter &rewriter) const final {
237+
mlir::Type ty = this->convertType(op.getType());
238+
return doRewrite(op, ty, adaptor, rewriter);
239+
}
240+
241+
virtual mlir::LogicalResult
242+
doRewrite(FromOp addr, mlir::Type ty, OpAdaptor adaptor,
243+
mlir::ConversionPatternRewriter &rewriter) const = 0;
244+
};
245+
246+
} // namespace fir
247+
248+
#endif // FORTRAN_OPTIMIZER_CODEGEN_FIROPPATTERNS_H

flang/include/flang/Optimizer/CodeGen/TypeConverter.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,8 @@ class LLVMTypeConverter : public mlir::LLVMTypeConverter {
9494
// to LLVM IR dialect here.
9595
//
9696
// fir.complex<T> | std.complex<T> --> llvm<"{t,t}">
97-
template <typename C> mlir::Type convertComplexType(C cmplx) const {
98-
LLVM_DEBUG(llvm::dbgs() << "type convert: " << cmplx << '\n');
97+
template <typename C>
98+
mlir::Type convertComplexType(C cmplx) const {
9999
auto eleTy = cmplx.getElementType();
100100
return convertType(specifics->complexMemoryType(eleTy));
101101
}

flang/lib/Optimizer/CodeGen/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ add_flang_library(FIRCodeGen
33
CGOps.cpp
44
CodeGen.cpp
55
CodeGenOpenMP.cpp
6+
FIROpPatterns.cpp
67
PreCGRewrite.cpp
78
TBAABuilder.cpp
89
Target.cpp

0 commit comments

Comments
 (0)