22#include "llvm/ADT/STLExtras.h"
36 if (!newShape.empty())
37 return input.getType();
45 return input.getType().clone(
shape);
58 bool inputIsStatic = inputType.hasStaticShape();
59 int64_t totalSize = inputIsStatic ? inputType.getNumElements() : -1;
71 return ShapedType::kDynamic;
75 int64_t totalSizeNoPlaceholder = -llvm::product_of(newShape);
79 if (totalSizeNoPlaceholder == 0)
84 return totalSize / totalSizeNoPlaceholder;
87 bool resultIsStatic = ShapedType::isStaticShape(resultShape);
92 if (!inputIsStatic && resultIsStatic)
93 resultShape[0] = ShapedType::kDynamic;
98 assert(!inputIsStatic || resultIsStatic);
101 return inputType.
clone(resultShape);
110 if (lhsShape.empty() || rhsShape.empty())
113 if (ShapedType::isDynamicShape(lhsShape) ||
114 ShapedType::isDynamicShape(rhsShape))
115 return lhsType.clone({ShapedType::kDynamic});
118 unsigned currLhsDim = 0, currRhsDim = 0;
119 while (currLhsDim < lhsShape.size() && currRhsDim < rhsShape.size()) {
120 int64_t rhsSize = rhsShape[currRhsDim];
121 int64_t lhsSize = lhsShape[currLhsDim];
122 while (lhsSize != rhsSize && currLhsDim < lhsShape.size() &&
123 currRhsDim < rhsShape.size()) {
124 if (lhsSize < rhsSize) {
126 if (currLhsDim < lhsShape.size()) {
127 lhsSize *= lhsShape[currLhsDim];
131 if (currRhsDim < rhsShape.size()) {
132 rhsSize *= rhsShape[currRhsDim];
136 if (lhsSize == rhsSize) {
137 intermediateShape.push_back(lhsSize);
145 for (; currLhsDim < lhsShape.size(); currLhsDim++) {
146 assert(lhsShape[currLhsDim] == 1);
148 for (; currRhsDim < rhsShape.size(); currRhsDim++) {
149 assert(rhsShape[currRhsDim] == 1);
152 return lhsType.clone(intermediateShape);
156createReassociationMapForCollapse(
OpBuilder &builder,
Type srcType,
158 auto srcShape = cast<TensorType>(srcType).getShape();
159 auto dstShape = cast<TensorType>(dstType).getShape();
161 if (srcShape.empty() || dstShape.empty())
164 if (ShapedType::isDynamicShape(srcShape) ||
165 ShapedType::isDynamicShape(dstShape)) {
166 assert(dstShape.size() == 1);
168 for (
auto i : llvm::seq<int64_t>(srcShape.size()))
174 unsigned currSrcDim = 0, currDstDim = 0;
175 while (currSrcDim < srcShape.size() && currDstDim < dstShape.size()) {
176 int64_t dstSize = dstShape[currDstDim];
177 int64_t srcSize = srcShape[currSrcDim];
178 while (srcSize < dstSize && currSrcDim < srcShape.size()) {
179 reassociationMap[currDstDim].push_back(
181 srcSize *= srcShape[currSrcDim];
183 if (srcSize == dstSize) {
184 reassociationMap[currDstDim].push_back(
188 if (currDstDim == dstShape.size() - 1 || dstShape[currDstDim + 1] != 1) {
189 while (currSrcDim < srcShape.size() && srcShape[currSrcDim] == 1) {
190 reassociationMap[currDstDim].push_back(
201 assert(currSrcDim == srcShape.size() && currDstDim == dstShape.size());
202 return reassociationMap;
209 auto reassociationMap =
210 createReassociationMapForCollapse(builder, input.
getType(), resultType);
211 return builder.
createOrFold<tensor::CollapseShapeOp>(loc, resultType, input,
219 auto reassociationMap =
220 createReassociationMapForCollapse(builder, resultType, input.
getType());
221 return builder.
createOrFold<tensor::ExpandShapeOp>(loc, resultType, input,
225class ReshapeConverter :
public OpConversionPattern<tosa::ReshapeOp> {
227 using OpConversionPattern<tosa::ReshapeOp>::OpConversionPattern;
230 matchAndRewrite(tosa::ReshapeOp reshape, OpAdaptor adaptor,
231 ConversionPatternRewriter &rewriter)
const final {
232 auto loc = reshape.getLoc();
234 getTypeConverter()->convertType<ShapedType>(reshape.getType());
236 return rewriter.notifyMatchFailure(reshape.getLoc(),
237 "could not convert result type");
239 auto input = dyn_cast<TypedValue<TensorType>>(adaptor.getInput1());
241 return rewriter.notifyMatchFailure(reshape.getLoc(),
242 "expected input type to be tensor");
245 llvm::SmallVector<int64_t> newShape;
252 auto inputType = inferReshapeInputType(input, newShape);
253 auto expandedType = inferReshapeExpandedType(inputType, newShape);
254 auto collapsedType = inferReshapeCollapsedType(inputType, expandedType);
258 rewriter.createOrFold<tensor::CastOp>(loc, inputType, input);
261 auto collapsed = createCollapse(rewriter, loc, collapsedType, castInput);
262 auto expanded = createExpand(rewriter, loc, expandedType, collapsed);
266 rewriter.createOrFold<tensor::CastOp>(loc, resultType, expanded);
267 rewriter.replaceOp(reshape,
result);
272class SliceConverter :
public OpConversionPattern<tosa::SliceOp> {
274 using OpConversionPattern<tosa::SliceOp>::OpConversionPattern;
277 matchAndRewrite(tosa::SliceOp sliceOp, OpAdaptor adaptor,
278 ConversionPatternRewriter &rewriter)
const final {
279 Location loc = sliceOp.getLoc();
280 Value input = adaptor.getInput1();
281 ShapedType resultType = cast<ShapedType>(sliceOp.getType());
282 if (llvm::isa<UnrankedTensorType>(resultType))
285 ElementsAttr startElems;
286 ElementsAttr sizeElems;
289 return rewriter.notifyMatchFailure(
290 sliceOp,
"start of slice must be a static ranked shape");
293 return rewriter.notifyMatchFailure(
294 sliceOp,
"size of slice must be a static ranked shape");
296 llvm::SmallVector<int64_t> sliceStarts =
297 llvm::to_vector(startElems.getValues<int64_t>());
298 llvm::SmallVector<int64_t> sliceSizes =
299 llvm::to_vector(sizeElems.getValues<int64_t>());
301 SmallVector<int64_t> strides, sizes;
302 strides.resize(cast<ShapedType>(sliceOp.getType()).getRank(), 1);
304 SmallVector<Value> dynSizes;
305 for (
const auto &i : llvm::enumerate(sliceSizes)) {
306 int64_t size = i.value();
307 size_t index = i.index();
308 sizes.push_back(size == -1 ? ShapedType::kDynamic : size);
309 if (ShapedType::isStatic(sizes.back()))
312 auto dim = tensor::DimOp::create(rewriter, loc, input, index);
313 auto offset = arith::ConstantOp::create(
314 rewriter, loc, rewriter.getIndexAttr(sliceStarts[index]));
315 dynSizes.push_back(arith::SubIOp::create(rewriter, loc, dim, offset));
318 auto newSliceOp = tensor::ExtractSliceOp::create(
319 rewriter, sliceOp.getLoc(), sliceOp.getType(), input,
ValueRange({}),
320 dynSizes,
ValueRange({}), rewriter.getDenseI64ArrayAttr(sliceStarts),
321 rewriter.getDenseI64ArrayAttr(sizes),
322 rewriter.getDenseI64ArrayAttr(strides));
325 Operation *startConstShape = sliceOp.getStart().getDefiningOp();
326 if (startConstShape->getResult(0).hasOneUse())
327 rewriter.eraseOp(startConstShape);
329 Operation *sizeConstShape = sliceOp.getSize().getDefiningOp();
331 rewriter.eraseOp(sizeConstShape);
333 rewriter.replaceOp(sliceOp, newSliceOp.getResult());
338class PadConverter :
public OpConversionPattern<tosa::PadOp> {
343 matchAndRewrite(tosa::PadOp padOp, OpAdaptor adaptor,
344 ConversionPatternRewriter &rewriter)
const final {
345 auto loc = padOp.getLoc();
346 auto input = padOp.getInput1();
348 ElementsAttr paddingElems;
350 return rewriter.notifyMatchFailure(
351 padOp,
"padding must be a static shape value");
353 llvm::SmallVector<int64_t> paddingVals;
354 for (
auto idx : paddingElems.getValues<IntegerAttr>()) {
355 paddingVals.push_back(
static_cast<int64_t
>(idx.getInt()));
360 if (llvm::any_of(paddingVals, [](int64_t val) {
return val < 0; })) {
362 arith::ConstantOp::create(rewriter, loc, rewriter.getBoolAttr(
false));
363 cf::AssertOp::create(
365 rewriter.getStringAttr(
"tosa.pad: padding must be non-negative"));
368 ShapedType inputTy = cast<ShapedType>(input.
getType());
369 int64_t rank = inputTy.getRank();
373 Value padConstant = rewriter.createOrFold<tensor::ExtractOp>(
374 loc, padOp.getPadConst(),
378 return rewriter.notifyMatchFailure(
379 padOp,
"tosa.pad was unable to determine the pad constant value.");
382 SmallVector<OpFoldResult, 3> lowValues;
383 SmallVector<OpFoldResult, 3> highValues;
385 lowValues.reserve(rank);
386 highValues.reserve(rank);
388 for (
int i = 0; i < rank; i++) {
389 Value lowVal = arith::ConstantOp::create(
390 rewriter, loc, rewriter.getIndexAttr(paddingVals[2 * i]));
391 Value highVal = arith::ConstantOp::create(
392 rewriter, loc, rewriter.getIndexAttr(paddingVals[2 * i + 1]));
393 lowValues.push_back(lowVal);
394 highValues.push_back(highVal);
397 auto newPadOp = tensor::PadOp::create(rewriter, loc, padOp.getType(), input,
398 lowValues, highValues, padConstant);
400 rewriter.replaceOp(padOp, newPadOp.getResult());
405struct ConcatConverter :
public OpConversionPattern<tosa::ConcatOp> {
406 using OpConversionPattern<tosa::ConcatOp>::OpConversionPattern;
409 matchAndRewrite(tosa::ConcatOp op, OpAdaptor adaptor,
410 ConversionPatternRewriter &rewriter)
const override {
412 getTypeConverter()->convertType<RankedTensorType>(op.getType());
416 rewriter.replaceOpWithNewOp<tensor::ConcatOp>(
417 op, resultType, rewriter.getI64IntegerAttr(op.getAxis()),
418 adaptor.getInput1());
428 ->
add<ConcatConverter, PadConverter, ReshapeConverter, SliceConverter>(
static LogicalResult fail(function_ref< InFlightDiagnostic()> emitError, const Twine &message)
Reports message through emitError if it is non-null, and returns failure.
AffineExpr getAffineDimExpr(unsigned position)
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
This class helps build Operations.
void createOrFold(SmallVectorImpl< Value > &results, Location location, Args &&...args)
Create an operation of specific op type at the current insertion point, and immediately try to fold i...
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
MLIRContext * getContext() const
RewritePatternSet & add(ConstructorArg &&arg, ConstructorArgs &&...args)
Add an instance of each of the pattern types 'Ts' to the pattern list with the given arguments.
Tensor types represent multi-dimensional arrays, and have two variants: RankedTensorType and Unranked...
ArrayRef< int64_t > getShape() const
Returns the shape of this tensor type.
RankedTensorType clone(ArrayRef< int64_t > shape, Type elementType) const
Return a clone of this type with the given new shape and element type.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Type getType() const
Return the type of this value.
bool hasOneUse() const
Returns true if this value has exactly one use.
static ConstantIndexOp create(OpBuilder &builder, Location location, int64_t value)
void populateTosaToTensorConversionPatterns(const TypeConverter &converter, RewritePatternSet *patterns)
bool getConstShapeValues(Operation *op, llvm::SmallVector< int64_t > &result_shape)
Include the generated interface declarations.
bool matchPattern(Value value, const Pattern &pattern)
Entry point for matching a pattern over a Value.
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.
detail::constant_op_matcher m_Constant()
Matches a constant foldable operation.