MLIR  21.0.0git
MemRefToEmitC.cpp
Go to the documentation of this file.
1 //===- MemRefToEmitC.cpp - MemRef to EmitC conversion ---------------------===//
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 // This file implements patterns to convert memref ops into emitc ops.
10 //
11 //===----------------------------------------------------------------------===//
12 
14 
18 #include "mlir/IR/Builders.h"
19 #include "mlir/IR/PatternMatch.h"
21 
22 using namespace mlir;
23 
24 namespace {
25 /// Implement the interface to convert MemRef to EmitC.
26 struct MemRefToEmitCDialectInterface : public ConvertToEmitCPatternInterface {
28 
29  /// Hook for derived dialect interface to provide conversion patterns
30  /// and mark dialect legal for the conversion target.
31  void populateConvertToEmitCConversionPatterns(
32  ConversionTarget &target, TypeConverter &typeConverter,
33  RewritePatternSet &patterns) const final {
36  }
37 };
38 } // namespace
39 
41  registry.addExtension(+[](MLIRContext *ctx, memref::MemRefDialect *dialect) {
42  dialect->addInterfaces<MemRefToEmitCDialectInterface>();
43  });
44 }
45 
46 //===----------------------------------------------------------------------===//
47 // Conversion Patterns
48 //===----------------------------------------------------------------------===//
49 
50 namespace {
51 struct ConvertAlloca final : public OpConversionPattern<memref::AllocaOp> {
53 
54  LogicalResult
55  matchAndRewrite(memref::AllocaOp op, OpAdaptor operands,
56  ConversionPatternRewriter &rewriter) const override {
57 
58  if (!op.getType().hasStaticShape()) {
59  return rewriter.notifyMatchFailure(
60  op.getLoc(), "cannot transform alloca with dynamic shape");
61  }
62 
63  if (op.getAlignment().value_or(1) > 1) {
64  // TODO: Allow alignment if it is not more than the natural alignment
65  // of the C array.
66  return rewriter.notifyMatchFailure(
67  op.getLoc(), "cannot transform alloca with alignment requirement");
68  }
69 
70  auto resultTy = getTypeConverter()->convertType(op.getType());
71  if (!resultTy) {
72  return rewriter.notifyMatchFailure(op.getLoc(), "cannot convert type");
73  }
74  auto noInit = emitc::OpaqueAttr::get(getContext(), "");
75  rewriter.replaceOpWithNewOp<emitc::VariableOp>(op, resultTy, noInit);
76  return success();
77  }
78 };
79 
80 struct ConvertGlobal final : public OpConversionPattern<memref::GlobalOp> {
82 
83  LogicalResult
84  matchAndRewrite(memref::GlobalOp op, OpAdaptor operands,
85  ConversionPatternRewriter &rewriter) const override {
86 
87  if (!op.getType().hasStaticShape()) {
88  return rewriter.notifyMatchFailure(
89  op.getLoc(), "cannot transform global with dynamic shape");
90  }
91 
92  if (op.getAlignment().value_or(1) > 1) {
93  // TODO: Extend GlobalOp to specify alignment via the `alignas` specifier.
94  return rewriter.notifyMatchFailure(
95  op.getLoc(), "global variable with alignment requirement is "
96  "currently not supported");
97  }
98  auto resultTy = getTypeConverter()->convertType(op.getType());
99  if (!resultTy) {
100  return rewriter.notifyMatchFailure(op.getLoc(),
101  "cannot convert result type");
102  }
103 
105  if (visibility != SymbolTable::Visibility::Public &&
106  visibility != SymbolTable::Visibility::Private) {
107  return rewriter.notifyMatchFailure(
108  op.getLoc(),
109  "only public and private visibility is currently supported");
110  }
111  // We are explicit in specifing the linkage because the default linkage
112  // for constants is different in C and C++.
113  bool staticSpecifier = visibility == SymbolTable::Visibility::Private;
114  bool externSpecifier = !staticSpecifier;
115 
116  Attribute initialValue = operands.getInitialValueAttr();
117  if (isa_and_present<UnitAttr>(initialValue))
118  initialValue = {};
119 
120  rewriter.replaceOpWithNewOp<emitc::GlobalOp>(
121  op, operands.getSymName(), resultTy, initialValue, externSpecifier,
122  staticSpecifier, operands.getConstant());
123  return success();
124  }
125 };
126 
127 struct ConvertGetGlobal final
128  : public OpConversionPattern<memref::GetGlobalOp> {
130 
131  LogicalResult
132  matchAndRewrite(memref::GetGlobalOp op, OpAdaptor operands,
133  ConversionPatternRewriter &rewriter) const override {
134 
135  auto resultTy = getTypeConverter()->convertType(op.getType());
136  if (!resultTy) {
137  return rewriter.notifyMatchFailure(op.getLoc(),
138  "cannot convert result type");
139  }
140  rewriter.replaceOpWithNewOp<emitc::GetGlobalOp>(op, resultTy,
141  operands.getNameAttr());
142  return success();
143  }
144 };
145 
146 struct ConvertLoad final : public OpConversionPattern<memref::LoadOp> {
148 
149  LogicalResult
150  matchAndRewrite(memref::LoadOp op, OpAdaptor operands,
151  ConversionPatternRewriter &rewriter) const override {
152 
153  auto resultTy = getTypeConverter()->convertType(op.getType());
154  if (!resultTy) {
155  return rewriter.notifyMatchFailure(op.getLoc(), "cannot convert type");
156  }
157 
158  auto arrayValue =
159  dyn_cast<TypedValue<emitc::ArrayType>>(operands.getMemref());
160  if (!arrayValue) {
161  return rewriter.notifyMatchFailure(op.getLoc(), "expected array type");
162  }
163 
164  auto subscript = rewriter.create<emitc::SubscriptOp>(
165  op.getLoc(), arrayValue, operands.getIndices());
166 
167  rewriter.replaceOpWithNewOp<emitc::LoadOp>(op, resultTy, subscript);
168  return success();
169  }
170 };
171 
172 struct ConvertStore final : public OpConversionPattern<memref::StoreOp> {
174 
175  LogicalResult
176  matchAndRewrite(memref::StoreOp op, OpAdaptor operands,
177  ConversionPatternRewriter &rewriter) const override {
178  auto arrayValue =
179  dyn_cast<TypedValue<emitc::ArrayType>>(operands.getMemref());
180  if (!arrayValue) {
181  return rewriter.notifyMatchFailure(op.getLoc(), "expected array type");
182  }
183 
184  auto subscript = rewriter.create<emitc::SubscriptOp>(
185  op.getLoc(), arrayValue, operands.getIndices());
186  rewriter.replaceOpWithNewOp<emitc::AssignOp>(op, subscript,
187  operands.getValue());
188  return success();
189  }
190 };
191 } // namespace
192 
194  typeConverter.addConversion(
195  [&](MemRefType memRefType) -> std::optional<Type> {
196  if (!memRefType.hasStaticShape() ||
197  !memRefType.getLayout().isIdentity() || memRefType.getRank() == 0 ||
198  llvm::any_of(memRefType.getShape(),
199  [](int64_t dim) { return dim == 0; })) {
200  return {};
201  }
202  Type convertedElementType =
203  typeConverter.convertType(memRefType.getElementType());
204  if (!convertedElementType)
205  return {};
206  return emitc::ArrayType::get(memRefType.getShape(),
207  convertedElementType);
208  });
209 
210  auto materializeAsUnrealizedCast = [](OpBuilder &builder, Type resultType,
211  ValueRange inputs,
212  Location loc) -> Value {
213  if (inputs.size() != 1)
214  return Value();
215 
216  return builder.create<UnrealizedConversionCastOp>(loc, resultType, inputs)
217  .getResult(0);
218  };
219 
220  typeConverter.addSourceMaterialization(materializeAsUnrealizedCast);
221  typeConverter.addTargetMaterialization(materializeAsUnrealizedCast);
222 }
223 
225  RewritePatternSet &patterns, const TypeConverter &converter) {
226  patterns.add<ConvertAlloca, ConvertGlobal, ConvertGetGlobal, ConvertLoad,
227  ConvertStore>(converter, patterns.getContext());
228 }
static MLIRContext * getContext(OpFoldResult val)
Attributes are known-constant values of operations.
Definition: Attributes.h:25
This class implements a pattern rewriter for use with ConversionPatterns.
This class describes a specific conversion target.
ConvertToEmitCPatternInterface(Dialect *dialect)
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.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Definition: Location.h:66
MLIRContext is the top-level object for a collection of MLIR operations.
Definition: MLIRContext.h:60
This class helps build Operations.
Definition: Builders.h:205
Operation * create(const OperationState &state)
Creates an operation given the fields represented as an OperationState.
Definition: Builders.cpp:453
OpConversionPattern is a wrapper around ConversionPattern that allows for matching and rewriting agai...
OpConversionPattern(MLIRContext *context, PatternBenefit benefit=1)
std::enable_if_t<!std::is_convertible< CallbackT, Twine >::value, LogicalResult > notifyMatchFailure(Location loc, CallbackT &&reasonCallback)
Used to notify the listener that the IR failed to be rewritten because of a match failure,...
Definition: PatternMatch.h:682
OpTy replaceOpWithNewOp(Operation *op, Args &&...args)
Replace the results of the given (original) op with a new op that is created without verification (re...
Definition: PatternMatch.h:500
static Visibility getSymbolVisibility(Operation *symbol)
Returns the visibility of the given symbol operation.
Visibility
An enumeration detailing the different visibility types that a symbol may have.
Definition: SymbolTable.h:90
@ Public
The symbol is public and may be referenced anywhere internal or external to the visible references in...
@ Private
The symbol is private and may only be referenced by SymbolRefAttrs local to the operations within the...
Type conversion class.
void addConversion(FnT &&callback)
Register a conversion function.
LogicalResult convertType(Type t, SmallVectorImpl< Type > &results) const
Convert the given type.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition: Types.h:74
This class provides an abstraction over the different types of ranges over Values.
Definition: ValueRange.h:387
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition: Value.h:96
Include the generated interface declarations.
void populateMemRefToEmitCTypeConversion(TypeConverter &typeConverter)
const FrozenRewritePatternSet & patterns
void populateMemRefToEmitCConversionPatterns(RewritePatternSet &patterns, const TypeConverter &converter)
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...
void registerConvertMemRefToEmitCInterface(DialectRegistry &registry)