MLIR 24.0.0git
OpenMPToLLVM.cpp
Go to the documentation of this file.
1//===- OpenMPToLLVM.cpp - conversion from OpenMP to LLVM dialect ----------===//
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
10
20#include "mlir/Pass/Pass.h"
21
22namespace mlir {
23#define GEN_PASS_DEF_CONVERTOPENMPTOLLVMPASS
24#include "mlir/Conversion/Passes.h.inc"
25} // namespace mlir
26
27using namespace mlir;
28
29namespace {
30
31static LogicalResult convertTypeAttr(Attribute &attr,
32 const TypeConverter &typeConverter) {
33 auto typeAttr = dyn_cast<TypeAttr>(attr);
34 if (!typeAttr)
35 return success();
36 Type convertedType = typeConverter.convertType(typeAttr.getValue());
37 if (!convertedType)
38 return failure();
39 attr = TypeAttr::get(convertedType);
40 return success();
41}
42
43static bool areTypeAttrsLegal(Operation *op,
44 const TypeConverter &typeConverter) {
45 bool inherentAttrsLegal = true;
46 op->getName().walkInherentAttrs(op, [&](StringRef, Attribute &attr) {
47 if (auto typeAttr = dyn_cast<TypeAttr>(attr))
48 inherentAttrsLegal &= typeConverter.isLegal(typeAttr.getValue());
49 });
50 return inherentAttrsLegal &&
51 llvm::all_of(op->getDiscardableAttrs(), [&](NamedAttribute attr) {
52 auto typeAttr = dyn_cast<TypeAttr>(attr.getValue());
53 return !typeAttr || typeConverter.isLegal(typeAttr.getValue());
54 });
55}
56
57/// A pattern that converts the result and operand types, attributes, and region
58/// arguments of an OpenMP operation to the LLVM dialect.
59///
60/// Attributes are copied verbatim by default, and only translated if they are
61/// type attributes.
62///
63/// Region bodies, if any, are not modified and expected to either be processed
64/// by the conversion infrastructure or already contain ops compatible with LLVM
65/// dialect types.
66template <typename T>
67struct OpenMPOpConversion : public ConvertOpToLLVMPattern<T> {
68 using ConvertOpToLLVMPattern<T>::ConvertOpToLLVMPattern;
69
70 OpenMPOpConversion(LLVMTypeConverter &typeConverter,
71 PatternBenefit benefit = 1)
72 : ConvertOpToLLVMPattern<T>(typeConverter, benefit) {
73 // Operations using CanonicalLoopInfoType are lowered only by
74 // mlir::translateModuleToLLVMIR() using the OpenMPIRBuilder. Until then,
75 // the type and operations using it must be preserved.
76 typeConverter.addConversion(
77 [&](::mlir::omp::CanonicalLoopInfoType type) { return type; });
78 }
79
80 LogicalResult
81 matchAndRewrite(T op, typename T::Adaptor adaptor,
82 ConversionPatternRewriter &rewriter) const override {
83 // Translate result types.
84 const TypeConverter *converter = ConvertToLLVMPattern::getTypeConverter();
85 SmallVector<Type> resTypes;
86 if (failed(converter->convertTypes(op->getResultTypes(), resTypes)))
87 return failure();
88
89 // Translate type attributes in the properties and discardable attributes.
90 // They are kept unmodified except if they are type attributes.
91 typename T::Properties convertedProperties = op.getProperties();
92 LogicalResult attrConversionResult = success();
93 T::walkInherentAttrs(
94 op.getContext(), convertedProperties, [&](StringRef, Attribute &attr) {
95 if (succeeded(attrConversionResult))
96 attrConversionResult = convertTypeAttr(attr, *converter);
97 });
98 if (failed(attrConversionResult))
99 return rewriter.notifyMatchFailure(op,
100 "failed to convert type in attribute");
101
102 SmallVector<NamedAttribute> convertedDiscardableAttrs;
103 for (NamedAttribute attr : op->getDiscardableAttrs()) {
104 Attribute convertedAttr = attr.getValue();
105 if (failed(convertTypeAttr(convertedAttr, *converter)))
106 return rewriter.notifyMatchFailure(
107 op, "failed to convert type in attribute");
108 convertedDiscardableAttrs.emplace_back(attr.getName(), convertedAttr);
109 }
110
111 // Translate operands.
112 SmallVector<Value> convertedOperands;
113 convertedOperands.reserve(op->getNumOperands());
114 for (auto [originalOperand, convertedOperand] :
115 llvm::zip_equal(op->getOperands(), adaptor.getOperands())) {
116 if (!originalOperand)
117 return failure();
118
119 // TODO: Revisit whether we need to trigger an error specifically for this
120 // set of operations. Consider removing this check or updating the list.
121 if constexpr (llvm::is_one_of<T, omp::AtomicUpdateOp, omp::AtomicWriteOp,
122 omp::FlushOp, omp::MapBoundsOp,
123 omp::ThreadprivateOp>::value) {
124 if (isa<MemRefType>(originalOperand.getType())) {
125 // TODO: Support memref type in variable operands
126 return rewriter.notifyMatchFailure(op, "memref is not supported yet");
127 }
128 }
129 convertedOperands.push_back(convertedOperand);
130 }
131
132 // Create new operation.
133 auto newOp = T::create(rewriter, op.getLoc(), resTypes, convertedOperands,
134 convertedProperties, convertedDiscardableAttrs);
135
136 // Translate regions.
137 for (auto [originalRegion, convertedRegion] :
138 llvm::zip_equal(op->getRegions(), newOp->getRegions())) {
139 rewriter.inlineRegionBefore(originalRegion, convertedRegion,
140 convertedRegion.end());
141 if (failed(rewriter.convertRegionTypes(&convertedRegion,
142 *this->getTypeConverter())))
143 return failure();
144 }
145
146 // Delete old operation and replace result uses with those of the new one.
147 rewriter.replaceOp(op, newOp->getResults());
148 return success();
149 }
150};
151
152} // namespace
153
155 ConversionTarget &target, const LLVMTypeConverter &typeConverter) {
156 target.addDynamicallyLegalOp<
157#define GET_OP_LIST
158#include "mlir/Dialect/OpenMP/OpenMPOps.cpp.inc"
159 >([&](Operation *op) {
160 return typeConverter.isLegal(op->getOperandTypes()) &&
161 typeConverter.isLegal(op->getResultTypes()) &&
162 llvm::all_of(op->getRegions(),
163 [&](Region &region) {
164 return typeConverter.isLegal(&region);
165 }) &&
166 areTypeAttrsLegal(op, typeConverter);
167 });
168}
169
170/// Add an `OpenMPOpConversion<T>` conversion pattern for each operation type
171/// passed as template argument.
172template <typename... Ts>
173static inline RewritePatternSet &
175 RewritePatternSet &patterns) {
176 return patterns.add<OpenMPOpConversion<Ts>...>(converter);
177}
178
180 RewritePatternSet &patterns) {
181 // This type is allowed when converting OpenMP to LLVM Dialect, it carries
182 // bounds information for map clauses and the operation and type are
183 // discarded on lowering to LLVM-IR from the OpenMP dialect.
184 converter.addConversion(
185 [&](omp::MapBoundsType type) -> Type { return type; });
186 converter.addConversion(
187 [&](omp::AffinityEntryType type) -> Type { return type; });
188 converter.addConversion([&](omp::IteratedType type) -> Type { return type; });
189
190 // Add conversions for all OpenMP operations.
192#define GET_OP_LIST
193#include "mlir/Dialect/OpenMP/OpenMPOps.cpp.inc"
194 >(converter, patterns);
195}
196
197namespace {
198struct ConvertOpenMPToLLVMPass
199 : public impl::ConvertOpenMPToLLVMPassBase<ConvertOpenMPToLLVMPass> {
200 using Base::Base;
201
202 void runOnOperation() override;
203};
204} // namespace
205
206void ConvertOpenMPToLLVMPass::runOnOperation() {
207 auto module = getOperation();
208
209 // Convert to OpenMP operations with LLVM IR dialect
210 RewritePatternSet patterns(&getContext());
211 LLVMTypeConverter converter(&getContext());
212 arith::populateArithToLLVMConversionPatterns(converter, patterns);
216 populateFuncToLLVMConversionPatterns(converter, patterns);
217 populateOpenMPToLLVMConversionPatterns(converter, patterns);
218
219 LLVMConversionTarget target(getContext());
220 target.addLegalOp<omp::BarrierOp, omp::FlushOp, omp::TaskwaitOp,
221 omp::TaskyieldOp, omp::TerminatorOp>();
223 if (failed(applyPartialConversion(module, target, std::move(patterns))))
224 signalPassFailure();
225}
226
227//===----------------------------------------------------------------------===//
228// ConvertToLLVMPatternInterface implementation
229//===----------------------------------------------------------------------===//
230namespace {
231/// Implement the interface to convert OpenMP to LLVM.
232struct OpenMPToLLVMDialectInterface : public ConvertToLLVMPatternInterface {
233 OpenMPToLLVMDialectInterface(Dialect *dialect)
234 : ConvertToLLVMPatternInterface(dialect) {}
235
236 void loadDependentDialects(MLIRContext *context) const final {
237 context->loadDialect<LLVM::LLVMDialect>();
238 }
239
240 /// Hook for derived dialect interface to provide conversion patterns
241 /// and mark dialect legal for the conversion target.
242 void populateConvertToLLVMConversionPatterns(
243 ConversionTarget &target, LLVMTypeConverter &typeConverter,
244 RewritePatternSet &patterns) const final {
246 populateOpenMPToLLVMConversionPatterns(typeConverter, patterns);
247 }
248};
249} // namespace
250
252 registry.addExtension(+[](MLIRContext *ctx, omp::OpenMPDialect *dialect) {
253 dialect->addInterfaces<OpenMPToLLVMDialectInterface>();
254 });
255}
return success()
b getContext())
static RewritePatternSet & addOpenMPOpConversions(LLVMTypeConverter &converter, RewritePatternSet &patterns)
Add an OpenMPOpConversion<T> conversion pattern for each operation type passed as template argument.
Attributes are known-constant values of operations.
Definition Attributes.h:25
Utility class for operation conversions targeting the LLVM dialect that match exactly one source oper...
Definition Pattern.h:233
const LLVMTypeConverter * getTypeConverter() const
Definition Pattern.cpp:29
The DialectRegistry maps a dialect namespace to a constructor for the matching dialect.
bool addExtension(TypeID extensionID, std::unique_ptr< DialectExtensionBase > extension)
Add the given extension to the registry.
Conversion from types to the LLVM IR dialect.
MLIRContext is the top-level object for a collection of MLIR operations.
Definition MLIRContext.h:63
NamedAttribute represents a combination of a name and an Attribute value.
Definition Attributes.h:164
void walkInherentAttrs(Operation *op, InherentAttrVisitor visitor) const
Visit the inherent attributes stored in the properties of op.
Operation is the basic unit of execution within MLIR.
Definition Operation.h:87
auto getDiscardableAttrs()
Return a range of all of discardable attributes on this operation.
Definition Operation.h:538
OperationName getName()
The name of an operation is the key identifier for it.
Definition Operation.h:115
This class contains a list of basic blocks and a link to the parent operation it is attached to.
Definition Region.h:26
RewritePatternSet & add(ConstructorArg &&arg, ConstructorArgs &&...args)
Add an instance of each of the pattern types 'Ts' to the pattern list with the given arguments.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition Types.h:74
void populateControlFlowToLLVMConversionPatterns(const LLVMTypeConverter &converter, RewritePatternSet &patterns)
Collect the patterns to convert from the ControlFlow dialect to LLVM.
void populateAssertToLLVMConversionPattern(const LLVMTypeConverter &converter, RewritePatternSet &patterns, bool abortOnFailure=true, SymbolTableCollection *symbolTables=nullptr)
Populate the cf.assert to LLVM conversion pattern.
detail::InFlightRemark failed(Location loc, RemarkOpts opts)
Report an optimization remark that failed.
Definition Remarks.h:732
Include the generated interface declarations.
void populateOpenMPToLLVMConversionPatterns(LLVMTypeConverter &converter, RewritePatternSet &patterns)
Populate the given list with patterns that convert from OpenMP to LLVM.
void populateFuncToLLVMConversionPatterns(const LLVMTypeConverter &converter, RewritePatternSet &patterns, SymbolTableCollection *symbolTables=nullptr)
Collect the patterns to convert from the Func dialect to LLVM.
void populateFinalizeMemRefToLLVMConversionPatterns(const LLVMTypeConverter &converter, RewritePatternSet &patterns, SymbolTableCollection *symbolTables=nullptr)
Collect a set of patterns to convert memory-related operations from the MemRef dialect to the LLVM di...
void registerConvertOpenMPToLLVMInterface(DialectRegistry &registry)
Registers the ConvertToLLVMPatternInterface interface in the OpenMP dialect.
void configureOpenMPToLLVMConversionLegality(ConversionTarget &target, const LLVMTypeConverter &typeConverter)
Configure dynamic conversion legality of regionless operations from OpenMP to LLVM.