31 return memRefType.hasStaticShape() && memRefType.getLayout().isIdentity() &&
32 memRefType.getRank() != 0 &&
33 !llvm::is_contained(memRefType.getShape(), 0);
43 void populateConvertToEmitCConversionPatterns(
54 dialect->addInterfaces<MemRefToEmitCDialectInterface>();
67 matchAndRewrite(memref::AllocaOp op, OpAdaptor operands,
70 if (!op.getType().hasStaticShape()) {
72 op.getLoc(),
"cannot transform alloca with dynamic shape");
75 if (op.getAlignment().value_or(1) > 1) {
79 op.getLoc(),
"cannot transform alloca with alignment requirement");
82 auto resultTy = getTypeConverter()->convertType(op.getType());
94 if (opTy.getRank() == 0) {
102 static Value calculateMemrefTotalSizeBytes(
Location loc, MemRefType memrefType,
105 "incompatible memref type for EmitC conversion");
106 emitc::CallOpaqueOp elementSize = emitc::CallOpaqueOp::create(
110 {TypeAttr::get(memrefType.getElementType())}));
113 int64_t numElements = std::accumulate(memrefType.getShape().begin(),
114 memrefType.getShape().end(), int64_t{1},
115 std::multiplies<int64_t>());
116 emitc::ConstantOp numElementsValue = emitc::ConstantOp::create(
117 builder, loc, indexType, builder.
getIndexAttr(numElements));
120 emitc::MulOp totalSizeBytes = emitc::MulOp::create(
121 builder, loc, sizeTType, elementSize.getResult(0), numElementsValue);
123 return totalSizeBytes.getResult();
126 static emitc::ApplyOp
130 emitc::ConstantOp zeroIndex = emitc::ConstantOp::create(
133 emitc::ArrayType arrayType = arrayValue.getType();
135 emitc::SubscriptOp subPtr =
136 emitc::SubscriptOp::create(builder, loc, arrayValue,
ValueRange(indices));
137 emitc::ApplyOp ptr = emitc::ApplyOp::create(
147 matchAndRewrite(memref::AllocOp allocOp, OpAdaptor operands,
150 MemRefType memrefType = allocOp.getType();
153 loc,
"incompatible memref type for EmitC conversion");
157 Type elementType = memrefType.getElementType();
159 emitc::CallOpaqueOp sizeofElementOp = emitc::CallOpaqueOp::create(
164 int64_t numElements = 1;
165 for (int64_t dimSize : memrefType.getShape()) {
166 numElements *= dimSize;
168 Value numElementsValue = emitc::ConstantOp::create(
169 rewriter, loc, indexType, rewriter.
getIndexAttr(numElements));
171 Value totalSizeBytes =
172 emitc::MulOp::create(rewriter, loc, sizeTType,
173 sizeofElementOp.getResult(0), numElementsValue);
175 emitc::CallOpaqueOp allocCall;
176 StringAttr allocFunctionName;
177 Value alignmentValue;
179 if (allocOp.getAlignment()) {
181 alignmentValue = emitc::ConstantOp::create(
182 rewriter, loc, sizeTType,
184 allocOp.getAlignment().value_or(0)));
185 argsVec.push_back(alignmentValue);
190 argsVec.push_back(totalSizeBytes);
193 allocCall = emitc::CallOpaqueOp::create(
197 allocFunctionName, args);
200 emitc::CastOp castOp = emitc::CastOp::create(
201 rewriter, loc, targetPointerType, allocCall.getResult(0));
212 matchAndRewrite(memref::CopyOp copyOp, OpAdaptor operands,
215 MemRefType srcMemrefType = cast<MemRefType>(copyOp.getSource().getType());
216 MemRefType targetMemrefType =
217 cast<MemRefType>(copyOp.getTarget().getType());
221 loc,
"incompatible source memref type for EmitC conversion");
225 loc,
"incompatible target memref type for EmitC conversion");
228 cast<TypedValue<emitc::ArrayType>>(operands.getSource());
229 emitc::ApplyOp srcPtr =
230 createPointerFromEmitcArray(loc, rewriter, srcArrayValue);
232 auto targetArrayValue =
233 cast<TypedValue<emitc::ArrayType>>(operands.getTarget());
234 emitc::ApplyOp targetPtr =
235 createPointerFromEmitcArray(loc, rewriter, targetArrayValue);
237 emitc::CallOpaqueOp memCpyCall = emitc::CallOpaqueOp::create(
240 targetPtr.getResult(), srcPtr.getResult(),
241 calculateMemrefTotalSizeBytes(loc, srcMemrefType, rewriter)});
243 rewriter.
replaceOp(copyOp, memCpyCall.getResults());
253 matchAndRewrite(memref::GlobalOp op, OpAdaptor operands,
255 MemRefType opTy = op.getType();
256 if (!op.getType().hasStaticShape()) {
258 op.getLoc(),
"cannot transform global with dynamic shape");
261 if (op.getAlignment().value_or(1) > 1) {
264 op.getLoc(),
"global variable with alignment requirement is "
265 "currently not supported");
268 Type resultTy = convertMemRefType(opTy, getTypeConverter());
272 "cannot convert result type");
280 "only public and private visibility is currently supported");
285 bool externSpecifier = !staticSpecifier;
287 Attribute initialValue = operands.getInitialValueAttr();
288 if (opTy.getRank() == 0) {
289 auto elementsAttr = llvm::cast<ElementsAttr>(*op.getInitialValue());
290 initialValue = elementsAttr.getSplatValue<
Attribute>();
292 if (isa_and_present<UnitAttr>(initialValue))
296 op, operands.getSymName(), resultTy, initialValue, externSpecifier,
297 staticSpecifier, operands.getConstant());
302 struct ConvertGetGlobal final
307 matchAndRewrite(memref::GetGlobalOp op, OpAdaptor operands,
310 MemRefType opTy = op.getType();
311 Type resultTy = convertMemRefType(opTy, getTypeConverter());
315 "cannot convert result type");
318 if (opTy.getRank() == 0) {
320 emitc::GetGlobalOp globalLValue = emitc::GetGlobalOp::create(
321 rewriter, op.getLoc(), lvalueType, operands.getNameAttr());
328 operands.getNameAttr());
337 matchAndRewrite(memref::LoadOp op, OpAdaptor operands,
340 auto resultTy = getTypeConverter()->convertType(op.getType());
346 dyn_cast<TypedValue<emitc::ArrayType>>(operands.getMemref());
351 auto subscript = emitc::SubscriptOp::create(
352 rewriter, op.getLoc(), arrayValue, operands.getIndices());
363 matchAndRewrite(memref::StoreOp op, OpAdaptor operands,
366 dyn_cast<TypedValue<emitc::ArrayType>>(operands.getMemref());
371 auto subscript = emitc::SubscriptOp::create(
372 rewriter, op.getLoc(), arrayValue, operands.getIndices());
374 operands.getValue());
382 [&](MemRefType memRefType) -> std::optional<Type> {
386 Type convertedElementType =
387 typeConverter.
convertType(memRefType.getElementType());
388 if (!convertedElementType)
391 convertedElementType);
394 auto materializeAsUnrealizedCast = [](
OpBuilder &builder,
Type resultType,
397 if (inputs.size() != 1)
400 return UnrealizedConversionCastOp::create(builder, loc, resultType, inputs)
410 patterns.add<ConvertAlloca, ConvertAlloc, ConvertCopy, ConvertGlobal,
static MLIRContext * getContext(OpFoldResult val)
static bool isMemRefTypeLegalForEmitC(MemRefType memRefType)
constexpr const char * mallocFunctionName
constexpr const char * alignedAllocFunctionName
Attributes are known-constant values of operations.
IntegerAttr getIndexAttr(int64_t value)
IntegerAttr getIntegerAttr(Type type, int64_t value)
StringAttr getStringAttr(const Twine &bytes)
MLIRContext * getContext() const
This class implements a pattern rewriter for use with ConversionPatterns.
void replaceOp(Operation *op, ValueRange newValues) override
Replace the given operation with the new values.
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...
MLIRContext is the top-level object for a collection of MLIR operations.
This class helps build Operations.
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,...
OpTy replaceOpWithNewOp(Operation *op, Args &&...args)
Replace the results of the given (original) op with a new op that is created without verification (re...
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.
@ 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...
void addConversion(FnT &&callback)
Register a conversion function.
LogicalResult convertType(Type t, SmallVectorImpl< Type > &results) const
Convert the given type.
void addSourceMaterialization(FnT &&callback)
All of the following materializations require function objects that are convertible to the following ...
void addTargetMaterialization(FnT &&callback)
This method registers a materialization that will be called when converting a value to a target type ...
This class provides an abstraction over the various different ranges of value types.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
This class provides an abstraction over the different types of ranges over Values.
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Include the generated interface declarations.
std::conditional_t< std::is_same_v< Ty, mlir::Type >, mlir::Value, detail::TypedValue< Ty > > TypedValue
If Ty is mlir::Type this will select Value instead of having a wrapper around it.
void populateMemRefToEmitCTypeConversion(TypeConverter &typeConverter)
Type getElementTypeOrSelf(Type type)
Return the element type or return the type itself.
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 ®istry)