[mlir] Simplify and better document std.view semantics

This [discussion](https://llvm.discourse.group/t/viewop-isnt-expressive-enough/991/2) raised some concerns with ViewOp.

In particular, the handling of offsets is incorrect and does not match the op description.
Note that with an elemental type change, offsets cannot be part of the type in general because sizeof(srcType) != sizeof(dstType).

Howerver, offset is a poorly chosen term for this purpose and is renamed to byte_shift.

Additionally, for all intended purposes, trying to support non-identity layouts for this op does not bring expressive power but rather increases code complexity.

This revision simplifies the existing semantics and implementation.
This simplification effort is voluntarily restrictive and acts as a stepping stone towards supporting richer semantics: treat the non-common cases as YAGNI for now and reevaluate based on concrete use cases once a round of simplification occurred.

Differential revision: https://reviews.llvm.org/D79541
This commit is contained in:
Nicolas Vasilache 2020-05-11 12:09:18 -04:00
parent f056dacbd7
commit 6ed61a26c2
15 changed files with 314 additions and 533 deletions

View File

@ -2982,63 +2982,58 @@ def ViewOp : Std_Op<"view", [
DeclareOpInterfaceMethods<ViewLikeOpInterface>, NoSideEffect]> {
let summary = "memref view operation";
let description = [{
The "view" operation converts a 1-D memref with i8 element type,
to an N-D memref with arbitrary element type. In addition, the ViewOp
supports the following arguments:
*) A single dynamic offset operand can be specified which represents a
a dynamic offset within the base 1-D memref at which to create the
resulting memref view.
*) A dynamic size operand must be specified for each dynamic dimension
The "view" operation extracts an N-D contiguous memref with empty layout map
with arbitrary element type from a 1-D contiguous memref with empty layout
map of i8 element type. The ViewOp supports the following arguments:
*) A single dynamic byte-shift operand must be specified which represents a
a shift of the base 1-D memref pointer from which to create the resulting
contiguous memref view with identity layout.
*) A dynamic size operand that must be specified for each dynamic dimension
in the resulting view memref type.
The "view" operation gives a structured indexing form to a flat 1-D buffer.
Unlike "subview" it can perform a type change. The type change behavior
requires the op to have special semantics because, e.g. a byte shift of 3
cannot be represented as an offset on f64.
For now, a "view" op:
1) Only takes a contiguous source memref with 0 offset and empty layout.
2) Must specify a byte_shift operand (in the future, a special integer
attribute may be added to support the folded case).
3) Returns a contiguous memref with 0 offset and empty layout.
Example:
```mlir
// Allocate a flat 1D/i8 memref.
%0 = alloc() : memref<2048xi8>
// ViewOp with static offset and sizes.
%1 = view %0[][] : memref<2048xi8> to memref<64x4xf32>
// ViewOp with dynamic offset and static sizes.
%1 = view %0[%offset_1024][] : memref<2048xi8> to memref<64x4xf32>
// ViewOp with dynamic offset and one dynamic size.
%2 = view %0[%offset_1024][%size0]
: memref<2048xi8> to memref<?x4xf32, (d0, d1)[s0] -> (d0 * 4 + d1 + s0)>
// ViewOp creating 3D shape where two of the dim sizes are dynamic.
// *) The dynamic offset specified in the ViewOp is applied to the
// base 1-D memref, and is represented by the symbol 's0' in the
// layout map of the ViewOp result memref type.
// *) The dynamic size for the second dimension induces a dynamic
// stride for the first dimension, which is represented by the
// symbol 's1' in the layout map of the ViewOp result memref type.
// Note that this dynamic stride will be computed from the view
// shape and dynamic sizes.
%3 = view %0[%offset_1024][%size0, %size1]
: memref<2048xi8> to memref<?x?x4xf32,
(d0, d1, d2)[s0, s1] -> (d0 * s1 + d1 * 4 + d2 + s0)>
// ViewOp with dynamic offset and two dynamic size.
%2 = view %0[%offset_1024][%size0, %size1] :
memref<2048xi8> to memref<?x4x?xf32>
```
}];
let arguments = (ins MemRefRankOf<[I8], [1]>:$source,
Variadic<Index>:$operands);
Index:$byte_shift,
Variadic<Index>:$sizes);
let results = (outs AnyMemRef);
let extraClassDeclaration = [{
/// The result of a view is always a memref.
MemRefType getType() { return getResult().getType().cast<MemRefType>(); }
/// Returns the dynamic offset for this view operation if specified.
/// Returns nullptr if no dynamic offset was specified.
Value getDynamicOffset();
/// Returns the starting operand list position of the dynamic size operands.
unsigned getDynamicSizesOperandStart() {
return getDynamicOffset() == nullptr ? 1 : 2;
}
/// Returns the dynamic sizes for this view operation.
/// Returns the dynamic sizes for this view operation. This is redundant
/// with `sizes` but needed in template implementations. More specifically:
/// ```
/// template <typename AnyMemRefDefOp>
/// bool isMemRefSizeValidSymbol(AnyMemRefDefOp memrefDefOp, unsigned index,
/// Region *region)
/// ```
operand_range getDynamicSizes() {
return {operand_begin() + getDynamicSizesOperandStart(), operand_end()};
return {sizes().begin(), sizes().end()};
}
}];

View File

@ -2676,35 +2676,31 @@ struct ViewOpLowering : public ConvertOpToLLVMPattern<ViewOp> {
auto successStrides = getStridesAndOffset(viewMemRefType, strides, offset);
if (failed(successStrides))
return op->emitWarning("cannot cast to non-strided shape"), failure();
assert(offset == 0 && "expected offset to be 0");
// Create the descriptor.
MemRefDescriptor sourceMemRef(adaptor.source());
auto targetMemRef = MemRefDescriptor::undef(rewriter, loc, targetDescTy);
// Field 1: Copy the allocated pointer, used for malloc/free.
Value extracted = sourceMemRef.allocatedPtr(rewriter, loc);
Value allocatedPtr = sourceMemRef.allocatedPtr(rewriter, loc);
Value bitcastPtr = rewriter.create<LLVM::BitcastOp>(
loc, targetElementTy.getPointerTo(), extracted);
loc, targetElementTy.getPointerTo(), allocatedPtr);
targetMemRef.setAllocatedPtr(rewriter, loc, bitcastPtr);
// Field 2: Copy the actual aligned pointer to payload.
extracted = sourceMemRef.alignedPtr(rewriter, loc);
Value alignedPtr = sourceMemRef.alignedPtr(rewriter, loc);
alignedPtr = rewriter.create<LLVM::GEPOp>(loc, alignedPtr.getType(),
alignedPtr, adaptor.byte_shift());
bitcastPtr = rewriter.create<LLVM::BitcastOp>(
loc, targetElementTy.getPointerTo(), extracted);
loc, targetElementTy.getPointerTo(), alignedPtr);
targetMemRef.setAlignedPtr(rewriter, loc, bitcastPtr);
// Field 3: Copy the offset in aligned pointer.
unsigned numDynamicSizes = llvm::size(viewOp.getDynamicSizes());
(void)numDynamicSizes;
bool hasDynamicOffset = offset == MemRefType::getDynamicStrideOrOffset();
auto sizeAndOffsetOperands = adaptor.operands();
assert(llvm::size(sizeAndOffsetOperands) ==
numDynamicSizes + (hasDynamicOffset ? 1 : 0));
Value baseOffset = !hasDynamicOffset
? createIndexConstant(rewriter, loc, offset)
// TODO(ntv): better adaptor.
: sizeAndOffsetOperands.front();
targetMemRef.setOffset(rewriter, loc, baseOffset);
// Field 3: The offset in the resulting type must be 0. This is because of
// the type change: an offset on srcType* may not be expressible as an
// offset on dstType*.
targetMemRef.setOffset(rewriter, loc,
createIndexConstant(rewriter, loc, offset));
// Early exit for 0-D corner case.
if (viewMemRefType.getRank() == 0)
@ -2714,14 +2710,10 @@ struct ViewOpLowering : public ConvertOpToLLVMPattern<ViewOp> {
if (strides.back() != 1)
return op->emitWarning("cannot cast to non-contiguous shape"), failure();
Value stride = nullptr, nextSize = nullptr;
// Drop the dynamic stride from the operand list, if present.
ArrayRef<Value> sizeOperands(sizeAndOffsetOperands);
if (hasDynamicOffset)
sizeOperands = sizeOperands.drop_front();
for (int i = viewMemRefType.getRank() - 1; i >= 0; --i) {
// Update size.
Value size =
getSize(rewriter, loc, viewMemRefType.getShape(), sizeOperands, i);
getSize(rewriter, loc, viewMemRefType.getShape(), adaptor.sizes(), i);
targetMemRef.setSize(rewriter, loc, i, size);
// Update stride.
stride = getStride(rewriter, loc, strides, nextSize, stride, i);

View File

@ -169,7 +169,7 @@ static PromotionInfo promoteSubviewAsNewBuffer(OpBuilder &b, Location loc,
dynamicBuffers, folder, alignment);
auto fullLocalView = folded_std_view(
folder, MemRefType::get(dynSizes, viewType.getElementType()), buffer,
fullSizes);
folded_std_constant_index(folder, 0), fullSizes);
SmallVector<Value, 4> zeros(fullSizes.size(), zero);
SmallVector<Value, 4> ones(fullSizes.size(), one);
auto partialLocalView =

View File

@ -2759,8 +2759,8 @@ static ParseResult parseViewOp(OpAsmParser &parser, OperationState &result) {
parser.parseOperandList(offsetInfo, OpAsmParser::Delimiter::Square))
return failure();
if (offsetInfo.size() > 1)
return parser.emitError(offsetLoc) << "expects 0 or 1 offset operand";
if (offsetInfo.size() != 1)
return parser.emitError(offsetLoc) << "expects 1 offset operand";
return failure(
parser.parseOperandList(sizesInfo, OpAsmParser::Delimiter::Square) ||
@ -2775,44 +2775,15 @@ static ParseResult parseViewOp(OpAsmParser &parser, OperationState &result) {
static void print(OpAsmPrinter &p, ViewOp op) {
p << op.getOperationName() << ' ' << op.getOperand(0) << '[';
auto dynamicOffset = op.getDynamicOffset();
if (dynamicOffset != nullptr)
p.printOperand(dynamicOffset);
p << "][" << op.getDynamicSizes() << ']';
p.printOperand(op.byte_shift());
p << "][" << op.sizes() << ']';
p.printOptionalAttrDict(op.getAttrs());
p << " : " << op.getOperand(0).getType() << " to " << op.getType();
}
Value ViewOp::getDynamicOffset() {
int64_t offset;
SmallVector<int64_t, 4> strides;
auto result =
succeeded(mlir::getStridesAndOffset(getType(), strides, offset));
assert(result);
if (result && offset == MemRefType::getDynamicStrideOrOffset())
return getOperand(1);
return nullptr;
}
static LogicalResult verifyDynamicStrides(MemRefType memrefType,
ArrayRef<int64_t> strides) {
unsigned rank = memrefType.getRank();
assert(rank == strides.size());
bool dynamicStrides = false;
for (int i = rank - 2; i >= 0; --i) {
// If size at dim 'i + 1' is dynamic, set the 'dynamicStrides' flag.
if (memrefType.isDynamicDim(i + 1))
dynamicStrides = true;
// If stride at dim 'i' is not dynamic, return error.
if (dynamicStrides && strides[i] != MemRefType::getDynamicStrideOrOffset())
return failure();
}
return success();
}
static LogicalResult verify(ViewOp op) {
auto baseType = op.getOperand(0).getType().cast<MemRefType>();
auto viewType = op.getResult().getType().cast<MemRefType>();
auto viewType = op.getType();
// The base memref should have identity layout map (or none).
if (baseType.getAffineMaps().size() > 1 ||
@ -2820,32 +2791,24 @@ static LogicalResult verify(ViewOp op) {
!baseType.getAffineMaps()[0].isIdentity()))
return op.emitError("unsupported map for base memref type ") << baseType;
// The result memref should have identity layout map (or none).
if (viewType.getAffineMaps().size() > 1 ||
(viewType.getAffineMaps().size() == 1 &&
!viewType.getAffineMaps()[0].isIdentity()))
return op.emitError("unsupported map for result memref type ") << viewType;
// The base memref and the view memref should be in the same memory space.
if (baseType.getMemorySpace() != viewType.getMemorySpace())
return op.emitError("different memory spaces specified for base memref "
"type ")
<< baseType << " and view memref type " << viewType;
// Verify that the result memref type has a strided layout map.
int64_t offset;
SmallVector<int64_t, 4> strides;
if (failed(getStridesAndOffset(viewType, strides, offset)))
return op.emitError("result type ") << viewType << " is not strided";
// Verify that we have the correct number of operands for the result type.
unsigned memrefOperandCount = 1;
// Verify that we have the correct number of sizes for the result type.
unsigned numDynamicDims = viewType.getNumDynamicDims();
unsigned dynamicOffsetCount =
offset == MemRefType::getDynamicStrideOrOffset() ? 1 : 0;
if (op.getNumOperands() !=
memrefOperandCount + numDynamicDims + dynamicOffsetCount)
return op.emitError("incorrect number of operands for type ") << viewType;
// Verify dynamic strides symbols were added to correct dimensions based
// on dynamic sizes.
if (failed(verifyDynamicStrides(viewType, strides)))
return op.emitError("incorrect dynamic strides in view memref type ")
if (op.sizes().size() != numDynamicDims)
return op.emitError("incorrect number of size operands for type ")
<< viewType;
return success();
}
@ -2866,42 +2829,23 @@ struct ViewOpShapeFolder : public OpRewritePattern<ViewOp> {
// Get result memref type.
auto memrefType = viewOp.getType();
if (memrefType.getAffineMaps().size() > 1)
return failure();
auto map = memrefType.getAffineMaps().empty()
? AffineMap::getMultiDimIdentityMap(memrefType.getRank(),
rewriter.getContext())
: memrefType.getAffineMaps()[0];
// Get offset from old memref view type 'memRefType'.
int64_t oldOffset;
SmallVector<int64_t, 4> oldStrides;
if (failed(getStridesAndOffset(memrefType, oldStrides, oldOffset)))
return failure();
assert(oldOffset == 0 && "Expected 0 offset");
SmallVector<Value, 4> newOperands;
// Fold dynamic offset operand if it is produced by a constant.
auto dynamicOffset = viewOp.getDynamicOffset();
int64_t newOffset = oldOffset;
unsigned dynamicOffsetOperandCount = 0;
if (dynamicOffset != nullptr) {
auto *defOp = dynamicOffset.getDefiningOp();
if (auto constantIndexOp = dyn_cast_or_null<ConstantIndexOp>(defOp)) {
// Dynamic offset will be folded into the map.
newOffset = constantIndexOp.getValue();
} else {
// Unable to fold dynamic offset. Add it to 'newOperands' list.
newOperands.push_back(dynamicOffset);
dynamicOffsetOperandCount = 1;
}
}
// Offset cannot be folded into result type.
// Fold any dynamic dim operands which are produced by a constant.
SmallVector<int64_t, 4> newShapeConstants;
newShapeConstants.reserve(memrefType.getRank());
unsigned dynamicDimPos = viewOp.getDynamicSizesOperandStart();
unsigned dynamicDimPos = 0;
unsigned rank = memrefType.getRank();
for (unsigned dim = 0, e = rank; dim < e; ++dim) {
int64_t dimSize = memrefType.getDimSize(dim);
@ -2910,46 +2854,29 @@ struct ViewOpShapeFolder : public OpRewritePattern<ViewOp> {
newShapeConstants.push_back(dimSize);
continue;
}
auto *defOp = viewOp.getOperand(dynamicDimPos).getDefiningOp();
auto *defOp = viewOp.sizes()[dynamicDimPos].getDefiningOp();
if (auto constantIndexOp = dyn_cast_or_null<ConstantIndexOp>(defOp)) {
// Dynamic shape dimension will be folded.
newShapeConstants.push_back(constantIndexOp.getValue());
} else {
// Dynamic shape dimension not folded; copy operand from old memref.
newShapeConstants.push_back(dimSize);
newOperands.push_back(viewOp.getOperand(dynamicDimPos));
newOperands.push_back(viewOp.sizes()[dynamicDimPos]);
}
dynamicDimPos++;
}
// Compute new strides based on 'newShapeConstants'.
SmallVector<int64_t, 4> newStrides(rank);
newStrides[rank - 1] = 1;
bool dynamicStrides = false;
for (int i = rank - 2; i >= 0; --i) {
if (ShapedType::isDynamic(newShapeConstants[i + 1]))
dynamicStrides = true;
if (dynamicStrides)
newStrides[i] = MemRefType::getDynamicStrideOrOffset();
else
newStrides[i] = newShapeConstants[i + 1] * newStrides[i + 1];
}
// Regenerate strided layout map with 'newStrides' and 'newOffset'.
map = makeStridedLinearLayoutMap(newStrides, newOffset,
rewriter.getContext());
// Create new memref type with constant folded dims and/or offset/strides.
MemRefType newMemRefType = MemRefType::Builder(memrefType)
.setShape(newShapeConstants)
.setAffineMaps({map});
(void)dynamicOffsetOperandCount; // unused in opt mode
assert(static_cast<int64_t>(newOperands.size()) ==
dynamicOffsetOperandCount + newMemRefType.getNumDynamicDims());
// Create new memref type with constant folded dims.
MemRefType newMemRefType =
MemRefType::Builder(memrefType).setShape(newShapeConstants);
// Nothing new, don't fold.
if (newMemRefType == memrefType)
return failure();
// Create new ViewOp.
auto newViewOp = rewriter.create<ViewOp>(viewOp.getLoc(), newMemRefType,
viewOp.getOperand(0), newOperands);
viewOp.getOperand(0),
viewOp.byte_shift(), newOperands);
// Insert a cast so we have the same type as the old memref type.
rewriter.replaceOpWithNewOp<MemRefCastOp>(viewOp, newViewOp,
viewOp.getType());
@ -2972,7 +2899,7 @@ struct ViewOpMemrefCastFolder : public OpRewritePattern<ViewOp> {
if (!allocOp)
return failure();
rewriter.replaceOpWithNewOp<ViewOp>(viewOp, viewOp.getType(), allocOperand,
viewOp.operands());
viewOp.byte_shift(), viewOp.sizes());
return success();
}
};

View File

@ -773,43 +773,30 @@ func @view(%arg0 : index, %arg1 : index, %arg2 : index) {
// CHECK: llvm.mlir.undef : !llvm<"{ i8*, i8*, i64, [1 x i64], [1 x i64] }">
%0 = alloc() : memref<2048xi8>
// Test two dynamic sizes and dynamic offset.
// Test two dynamic sizes.
// CHECK: llvm.mlir.undef : !llvm<"{ float*, float*, i64, [2 x i64], [2 x i64] }">
// CHECK: llvm.extractvalue %{{.*}}[1] : !llvm<"{ i8*, i8*, i64, [1 x i64], [1 x i64] }">
// CHECK: llvm.bitcast %{{.*}} : !llvm<"i8*"> to !llvm<"float*">
// CHECK: llvm.insertvalue %{{.*}}, %{{.*}}[1] : !llvm<"{ float*, float*, i64, [2 x i64], [2 x i64] }">
// CHECK: llvm.insertvalue %[[ARG2]], %{{.*}}[2] : !llvm<"{ float*, float*, i64, [2 x i64], [2 x i64] }">
// CHECK: %[[BASE_PTR:.*]] = llvm.extractvalue %{{.*}}[1] : !llvm<"{ i8*, i8*, i64, [1 x i64], [1 x i64] }">
// CHECK: %[[SHIFTED_BASE_PTR:.*]] = llvm.getelementptr %[[BASE_PTR]][%[[ARG2]]] : (!llvm<"i8*">, !llvm.i64) -> !llvm<"i8*">
// CHECK: %[[CAST_SHIFTED_BASE_PTR:.*]] = llvm.bitcast %[[SHIFTED_BASE_PTR]] : !llvm<"i8*"> to !llvm<"float*">
// CHECK: llvm.insertvalue %[[CAST_SHIFTED_BASE_PTR]], %{{.*}}[1] : !llvm<"{ float*, float*, i64, [2 x i64], [2 x i64] }">
// CHECK: %[[C0:.*]] = llvm.mlir.constant(0 : index) : !llvm.i64
// CHECK: llvm.insertvalue %[[C0]], %{{.*}}[2] : !llvm<"{ float*, float*, i64, [2 x i64], [2 x i64] }">
// CHECK: llvm.insertvalue %[[ARG1]], %{{.*}}[3, 1] : !llvm<"{ float*, float*, i64, [2 x i64], [2 x i64] }">
// CHECK: llvm.mlir.constant(1 : index) : !llvm.i64
// CHECK: llvm.insertvalue %{{.*}}, %{{.*}}[4, 1] : !llvm<"{ float*, float*, i64, [2 x i64], [2 x i64] }">
// CHECK: llvm.insertvalue %[[ARG0]], %{{.*}}[3, 0] : !llvm<"{ float*, float*, i64, [2 x i64], [2 x i64] }">
// CHECK: llvm.mul %{{.*}}, %[[ARG1]]
// CHECK: llvm.insertvalue %{{.*}}, %{{.*}}[4, 0] : !llvm<"{ float*, float*, i64, [2 x i64], [2 x i64] }">
%1 = view %0[%arg2][%arg0, %arg1]
: memref<2048xi8> to memref<?x?xf32, affine_map<(d0, d1)[s0, s1] -> (d0 * s0 + d1 + s1)>>
%1 = view %0[%arg2][%arg0, %arg1] : memref<2048xi8> to memref<?x?xf32>
// Test two dynamic sizes and static offset.
// Test one dynamic size.
// CHECK: llvm.mlir.undef : !llvm<"{ float*, float*, i64, [2 x i64], [2 x i64] }">
// CHECK: llvm.extractvalue %{{.*}}[1] : !llvm<"{ i8*, i8*, i64, [1 x i64], [1 x i64] }">
// CHECK: llvm.bitcast %{{.*}} : !llvm<"i8*"> to !llvm<"float*">
// CHECK: llvm.insertvalue %{{.*}}, %{{.*}}[1] : !llvm<"{ float*, float*, i64, [2 x i64], [2 x i64] }">
// CHECK: llvm.mlir.constant(0 : index) : !llvm.i64
// CHECK: llvm.insertvalue %{{.*}}, %{{.*}}[2] : !llvm<"{ float*, float*, i64, [2 x i64], [2 x i64] }">
// CHECK: llvm.insertvalue %{{.*}}, %{{.*}}[3, 1] : !llvm<"{ float*, float*, i64, [2 x i64], [2 x i64] }">
// CHECK: llvm.mlir.constant(1 : index) : !llvm.i64
// CHECK: llvm.insertvalue %{{.*}}, %{{.*}}[4, 1] : !llvm<"{ float*, float*, i64, [2 x i64], [2 x i64] }">
// CHECK: llvm.insertvalue %arg0, %{{.*}}[3, 0] : !llvm<"{ float*, float*, i64, [2 x i64], [2 x i64] }">
// CHECK: llvm.mul %{{.*}}, %[[ARG1]]
// CHECK: llvm.insertvalue %{{.*}}, %{{.*}}[4, 0] : !llvm<"{ float*, float*, i64, [2 x i64], [2 x i64] }">
%2 = view %0[][%arg0, %arg1]
: memref<2048xi8> to memref<?x?xf32, affine_map<(d0, d1)[s0] -> (d0 * s0 + d1)>>
// Test one dynamic size and dynamic offset.
// CHECK: llvm.mlir.undef : !llvm<"{ float*, float*, i64, [2 x i64], [2 x i64] }">
// CHECK: llvm.extractvalue %{{.*}}[1] : !llvm<"{ i8*, i8*, i64, [1 x i64], [1 x i64] }">
// CHECK: llvm.bitcast %{{.*}} : !llvm<"i8*"> to !llvm<"float*">
// CHECK: llvm.insertvalue %{{.*}}, %{{.*}}[1] : !llvm<"{ float*, float*, i64, [2 x i64], [2 x i64] }">
// CHECK: llvm.insertvalue %[[ARG2]], %{{.*}}[2] : !llvm<"{ float*, float*, i64, [2 x i64], [2 x i64] }">
// CHECK: %[[BASE_PTR_2:.*]] = llvm.extractvalue %{{.*}}[1] : !llvm<"{ i8*, i8*, i64, [1 x i64], [1 x i64] }">
// CHECK: %[[SHIFTED_BASE_PTR_2:.*]] = llvm.getelementptr %[[BASE_PTR_2]][%[[ARG2]]] : (!llvm<"i8*">, !llvm.i64) -> !llvm<"i8*">
// CHECK: %[[CAST_SHIFTED_BASE_PTR_2:.*]] = llvm.bitcast %[[SHIFTED_BASE_PTR_2]] : !llvm<"i8*"> to !llvm<"float*">
// CHECK: llvm.insertvalue %[[CAST_SHIFTED_BASE_PTR_2]], %{{.*}}[1] : !llvm<"{ float*, float*, i64, [2 x i64], [2 x i64] }">
// CHECK: %[[C0_2:.*]] = llvm.mlir.constant(0 : index) : !llvm.i64
// CHECK: llvm.insertvalue %[[C0_2]], %{{.*}}[2] : !llvm<"{ float*, float*, i64, [2 x i64], [2 x i64] }">
// CHECK: llvm.insertvalue %[[ARG1]], %{{.*}}[3, 1] : !llvm<"{ float*, float*, i64, [2 x i64], [2 x i64] }">
// CHECK: llvm.mlir.constant(1 : index) : !llvm.i64
// CHECK: llvm.insertvalue %{{.*}}, %{{.*}}[4, 1] : !llvm<"{ float*, float*, i64, [2 x i64], [2 x i64] }">
@ -817,33 +804,16 @@ func @view(%arg0 : index, %arg1 : index, %arg2 : index) {
// CHECK: llvm.insertvalue %{{.*}}, %{{.*}}[3, 0] : !llvm<"{ float*, float*, i64, [2 x i64], [2 x i64] }">
// CHECK: llvm.mul %{{.*}}, %[[ARG1]]
// CHECK: llvm.insertvalue %{{.*}}, %{{.*}}[4, 0] : !llvm<"{ float*, float*, i64, [2 x i64], [2 x i64] }">
%3 = view %0[%arg2][%arg1]
: memref<2048xi8> to memref<4x?xf32, affine_map<(d0, d1)[s0, s1] -> (d0 * s0 + d1 + s1)>>
%3 = view %0[%arg2][%arg1] : memref<2048xi8> to memref<4x?xf32>
// Test one dynamic size and static offset.
// Test static sizes.
// CHECK: llvm.mlir.undef : !llvm<"{ float*, float*, i64, [2 x i64], [2 x i64] }">
// CHECK: llvm.extractvalue %{{.*}}[1] : !llvm<"{ i8*, i8*, i64, [1 x i64], [1 x i64] }">
// CHECK: llvm.bitcast %{{.*}} : !llvm<"i8*"> to !llvm<"float*">
// CHECK: llvm.insertvalue %{{.*}}, %{{.*}}[1] : !llvm<"{ float*, float*, i64, [2 x i64], [2 x i64] }">
// CHECK: llvm.mlir.constant(0 : index) : !llvm.i64
// CHECK: llvm.insertvalue %{{.*}}, %{{.*}}[2] : !llvm<"{ float*, float*, i64, [2 x i64], [2 x i64] }">
// CHECK: llvm.mlir.constant(16 : index) : !llvm.i64
// CHECK: llvm.insertvalue %{{.*}}, %{{.*}}[3, 1] : !llvm<"{ float*, float*, i64, [2 x i64], [2 x i64] }">
// CHECK: llvm.mlir.constant(1 : index) : !llvm.i64
// CHECK: llvm.insertvalue %{{.*}}, %{{.*}}[4, 1] : !llvm<"{ float*, float*, i64, [2 x i64], [2 x i64] }">
// CHECK: llvm.insertvalue %[[ARG0]], %{{.*}}[3, 0] : !llvm<"{ float*, float*, i64, [2 x i64], [2 x i64] }">
// CHECK: llvm.mlir.constant(4 : index) : !llvm.i64
// CHECK: llvm.insertvalue %{{.*}}, %{{.*}}[4, 0] : !llvm<"{ float*, float*, i64, [2 x i64], [2 x i64] }">
%4 = view %0[][%arg0]
: memref<2048xi8> to memref<?x16xf32, affine_map<(d0, d1) -> (d0 * 4 + d1)>>
// Test static sizes and static offset.
// CHECK: llvm.mlir.undef : !llvm<"{ float*, float*, i64, [2 x i64], [2 x i64] }">
// CHECK: llvm.extractvalue %{{.*}}[1] : !llvm<"{ i8*, i8*, i64, [1 x i64], [1 x i64] }">
// CHECK: llvm.bitcast %{{.*}} : !llvm<"i8*"> to !llvm<"float*">
// CHECK: llvm.insertvalue %{{.*}}, %{{.*}}[1] : !llvm<"{ float*, float*, i64, [2 x i64], [2 x i64] }">
// CHECK: llvm.mlir.constant(0 : index) : !llvm.i64
// CHECK: llvm.insertvalue %{{.*}}, %{{.*}}[2] : !llvm<"{ float*, float*, i64, [2 x i64], [2 x i64] }">
// CHECK: %[[BASE_PTR_3:.*]] = llvm.extractvalue %{{.*}}[1] : !llvm<"{ i8*, i8*, i64, [1 x i64], [1 x i64] }">
// CHECK: %[[SHIFTED_BASE_PTR_3:.*]] = llvm.getelementptr %[[BASE_PTR_3]][%[[ARG2]]] : (!llvm<"i8*">, !llvm.i64) -> !llvm<"i8*">
// CHECK: %[[CAST_SHIFTED_BASE_PTR_3:.*]] = llvm.bitcast %[[SHIFTED_BASE_PTR_3]] : !llvm<"i8*"> to !llvm<"float*">
// CHECK: llvm.insertvalue %[[CAST_SHIFTED_BASE_PTR_3]], %{{.*}}[1] : !llvm<"{ float*, float*, i64, [2 x i64], [2 x i64] }">
// CHECK: %[[C0_3:.*]] = llvm.mlir.constant(0 : index) : !llvm.i64
// CHECK: llvm.insertvalue %[[C0_3]], %{{.*}}[2] : !llvm<"{ float*, float*, i64, [2 x i64], [2 x i64] }">
// CHECK: llvm.mlir.constant(4 : index) : !llvm.i64
// CHECK: llvm.insertvalue %{{.*}}, %{{.*}}[3, 1] : !llvm<"{ float*, float*, i64, [2 x i64], [2 x i64] }">
// CHECK: llvm.mlir.constant(1 : index) : !llvm.i64
@ -852,23 +822,7 @@ func @view(%arg0 : index, %arg1 : index, %arg2 : index) {
// CHECK: llvm.insertvalue %{{.*}}, %{{.*}}[3, 0] : !llvm<"{ float*, float*, i64, [2 x i64], [2 x i64] }">
// CHECK: llvm.mlir.constant(4 : index) : !llvm.i64
// CHECK: llvm.insertvalue %{{.*}}, %{{.*}}[4, 0] : !llvm<"{ float*, float*, i64, [2 x i64], [2 x i64] }">
%5 = view %0[][]
: memref<2048xi8> to memref<64x4xf32, affine_map<(d0, d1) -> (d0 * 4 + d1)>>
// Test dynamic everything.
// CHECK: llvm.mlir.undef : !llvm<"{ float*, float*, i64, [2 x i64], [2 x i64] }">
// CHECK: llvm.extractvalue %{{.*}}[1] : !llvm<"{ i8*, i8*, i64, [1 x i64], [1 x i64] }">
// CHECK: llvm.bitcast %{{.*}} : !llvm<"i8*"> to !llvm<"float*">
// CHECK: llvm.insertvalue %{{.*}}, %{{.*}}[1] : !llvm<"{ float*, float*, i64, [2 x i64], [2 x i64] }">
// CHECK: llvm.insertvalue %[[ARG2]], %{{.*}}[2] : !llvm<"{ float*, float*, i64, [2 x i64], [2 x i64] }">
// CHECK: llvm.insertvalue %[[ARG1]], %{{.*}}[3, 1] : !llvm<"{ float*, float*, i64, [2 x i64], [2 x i64] }">
// CHECK: %[[STRIDE_1:.*]] = llvm.mlir.constant(1 : index) : !llvm.i64
// CHECK: llvm.insertvalue %[[STRIDE_1]], %{{.*}}[4, 1] : !llvm<"{ float*, float*, i64, [2 x i64], [2 x i64] }">
// CHECK: llvm.insertvalue %[[ARG0]], %{{.*}}[3, 0] : !llvm<"{ float*, float*, i64, [2 x i64], [2 x i64] }">
// CHECK: llvm.mul %[[STRIDE_1]], %[[ARG1]] : !llvm.i64
// CHECK: llvm.insertvalue %{{.*}}, %{{.*}}[4, 0] : !llvm<"{ float*, float*, i64, [2 x i64], [2 x i64] }">
%6 = view %0[%arg2][%arg0, %arg1]
: memref<2048xi8> to memref<?x?xf32, affine_map<(d0, d1)[s0, s1] -> (d0 * s0 + d1 + s1)>>
%5 = view %0[%arg2][] : memref<2048xi8> to memref<64x4xf32>
return
}

View File

@ -3,7 +3,6 @@
// Test that we can lower all the way to LLVM without crashing, don't check results here.
// RUN: mlir-opt %s -convert-linalg-to-affine-loops -convert-linalg-to-llvm -o=/dev/null 2>&1
// CHECK-DAG: #[[strided2D:.*]] = affine_map<(d0, d1)[s0, s1] -> (d0 * s1 + s0 + d1)>
// CHECK-DAG: #[[strided3D:.*]] = affine_map<(d0, d1, d2)[s0, s1, s2] -> (d0 * s1 + s0 + d1 * s2 + d2)>
// CHECK-DAG: #[[stride2Dilation1:.*]] = affine_map<(d0, d1) -> (d0 * 2 + d1)>
@ -13,10 +12,10 @@
func @matmul(%arg0: memref<?xi8>, %M: index, %N: index, %K: index) {
%c0 = constant 0 : index
%c1 = constant 1 : index
%A = view %arg0[%c0][%M, %K] : memref<?xi8> to memref<?x?xf32, offset: ?, strides: [?, 1]>
%B = view %arg0[%c0][%K, %N] : memref<?xi8> to memref<?x?xf32, offset: ?, strides: [?, 1]>
%C = view %arg0[%c0][%M, %N] : memref<?xi8> to memref<?x?xf32, offset: ?, strides: [?, 1]>
linalg.matmul(%A, %B, %C) : memref<?x?xf32, offset: ?, strides: [?, 1]>, memref<?x?xf32, offset: ?, strides: [?, 1]>, memref<?x?xf32, offset: ?, strides: [?, 1]>
%A = view %arg0[%c0][%M, %K] : memref<?xi8> to memref<?x?xf32>
%B = view %arg0[%c0][%K, %N] : memref<?xi8> to memref<?x?xf32>
%C = view %arg0[%c0][%M, %N] : memref<?xi8> to memref<?x?xf32>
linalg.matmul(%A, %B, %C) : memref<?x?xf32>, memref<?x?xf32>, memref<?x?xf32>
return
}
@ -24,18 +23,18 @@ func @matmul(%arg0: memref<?xi8>, %M: index, %N: index, %K: index) {
// CHECK-SAME: [[M:arg[0-9]+]]: index
// CHECK-SAME: [[N:arg[0-9]+]]: index
// CHECK-SAME: [[K:arg[0-9]+]]: index
// CHECK: %[[A:.*]] = std.view %{{.*}}[{{.*}}] : memref<?xi8> to memref<?x?xf32, #[[strided2D]]>
// CHECK: %[[B:.*]] = std.view %{{.*}}[{{.*}}] : memref<?xi8> to memref<?x?xf32, #[[strided2D]]>
// CHECK: %[[C:.*]] = std.view %{{.*}}[{{.*}}] : memref<?xi8> to memref<?x?xf32, #[[strided2D]]>
// CHECK: %[[A:.*]] = std.view %{{.*}}[{{.*}}] : memref<?xi8> to memref<?x?xf32>
// CHECK: %[[B:.*]] = std.view %{{.*}}[{{.*}}] : memref<?xi8> to memref<?x?xf32>
// CHECK: %[[C:.*]] = std.view %{{.*}}[{{.*}}] : memref<?xi8> to memref<?x?xf32>
// CHECK: affine.for %{{.*}} = 0 to %{{.*}} {
// CHECK: affine.for %{{.*}} = 0 to %{{.*}} {
// CHECK: affine.for %{{.*}} = 0 to %{{.*}} {
// CHECK-DAG: %[[a:.*]] = affine.load %[[A]][%{{.*}}, %{{.*}}] : memref<?x?xf32, #[[strided2D]]>
// CHECK-DAG: %[[b:.*]] = affine.load %[[B]][%{{.*}}, %{{.*}}] : memref<?x?xf32, #[[strided2D]]>
// CHECK-DAG: %[[a:.*]] = affine.load %[[A]][%{{.*}}, %{{.*}}] : memref<?x?xf32>
// CHECK-DAG: %[[b:.*]] = affine.load %[[B]][%{{.*}}, %{{.*}}] : memref<?x?xf32>
// CHECK-DAG: %[[inc:.*]] = mulf %[[a]], %[[b]] : f32
// CHECK-DAG: %[[c:.*]] = affine.load %[[C]][%{{.*}}, %{{.*}}] : memref<?x?xf32, #[[strided2D]]>
// CHECK-DAG: %[[c:.*]] = affine.load %[[C]][%{{.*}}, %{{.*}}] : memref<?x?xf32>
// CHECK-DAG: %[[res:.*]] = addf %[[c]], %[[inc]] : f32
// CHECK: affine.store %[[res]], %[[C]][%{{.*}}, %{{.*}}] : memref<?x?xf32, #[[strided2D]]>
// CHECK: affine.store %[[res]], %[[C]][%{{.*}}, %{{.*}}] : memref<?x?xf32>
func @conv_view3(%arg0: memref<?x?x?xf32, offset: ?, strides: [?, ?, 1]>, %arg1: memref<?x?x?xf32, offset: ?, strides: [?, ?, 1]>, %arg2: memref<?x?x?xf32, offset: ?, strides: [?, ?, 1]>) {
linalg.conv(%arg0, %arg1, %arg2) {strides = [2]}: memref<?x?x?xf32, offset: ?, strides: [?, ?, 1]>, memref<?x?x?xf32, offset: ?, strides: [?, ?, 1]>, memref<?x?x?xf32, offset: ?, strides: [?, ?, 1]>

View File

@ -7,7 +7,7 @@ func @memref_cast(%a: index, %b: index) -> memref<?x?xf32> {
%c8 = constant 8 : index
%c16 = constant 16 : index
%1 = alloc (%b) : memref<?xi8>
%2 = view %1[][] : memref<?xi8> to memref<16x16xf32>
%2 = view %1[%c0][] : memref<?xi8> to memref<16x16xf32>
%3 = memref_cast %2 : memref<16x16xf32> to memref<?x?xf32>
%r0 = linalg.range %c0:%c8:%c1 : !linalg.range

View File

@ -30,104 +30,104 @@
func @matmul(%arg0: memref<?xi8>, %M: index, %N: index, %K: index) {
%c0 = constant 0 : index
%c1 = constant 1 : index
%A = view %arg0[%c0][%M, %K] : memref<?xi8> to memref<?x?xf32, offset: ?, strides: [?, 1]>
%B = view %arg0[%c0][%K, %N] : memref<?xi8> to memref<?x?xf32, offset: ?, strides: [?, 1]>
%C = view %arg0[%c0][%M, %N] : memref<?xi8> to memref<?x?xf32, offset: ?, strides: [?, 1]>
linalg.matmul(%A, %B, %C) : memref<?x?xf32, offset: ?, strides: [?, 1]>, memref<?x?xf32, offset: ?, strides: [?, 1]>, memref<?x?xf32, offset: ?, strides: [?, 1]>
%A = view %arg0[%c0][%M, %K] : memref<?xi8> to memref<?x?xf32>
%B = view %arg0[%c0][%K, %N] : memref<?xi8> to memref<?x?xf32>
%C = view %arg0[%c0][%M, %N] : memref<?xi8> to memref<?x?xf32>
linalg.matmul(%A, %B, %C) : memref<?x?xf32>, memref<?x?xf32>, memref<?x?xf32>
return
}
// CHECKLOOP-LABEL: func @matmul(%{{.*}}: memref<?xi8>,
// CHECKLOOP-SAME: [[M:arg[0-9]+]]: index
// CHECKLOOP-SAME: [[N:arg[0-9]+]]: index
// CHECKLOOP-SAME: [[K:arg[0-9]+]]: index
// CHECKLOOP: %[[A:.*]] = std.view %{{.*}}[{{.*}}] : memref<?xi8> to memref<?x?xf32, #[[strided2D]]>
// CHECKLOOP: %[[B:.*]] = std.view %{{.*}}[{{.*}}] : memref<?xi8> to memref<?x?xf32, #[[strided2D]]>
// CHECKLOOP: %[[C:.*]] = std.view %{{.*}}[{{.*}}] : memref<?xi8> to memref<?x?xf32, #[[strided2D]]>
// CHECKLOOP: %[[A:.*]] = std.view %{{.*}}[{{.*}}] : memref<?xi8> to memref<?x?xf32>
// CHECKLOOP: %[[B:.*]] = std.view %{{.*}}[{{.*}}] : memref<?xi8> to memref<?x?xf32>
// CHECKLOOP: %[[C:.*]] = std.view %{{.*}}[{{.*}}] : memref<?xi8> to memref<?x?xf32>
// CHECKLOOP: loop.for %{{.*}} = %{{.*}} to %[[M]] step %{{.*}} {
// CHECKLOOP: loop.for %{{.*}} = %{{.*}} to %[[N]] step %{{.*}} {
// CHECKLOOP: loop.for %{{.*}} = %{{.*}} to %[[K]] step %{{.*}} {
// CHECKLOOP-DAG: %[[a:.*]] = load %[[A]][%{{.*}}, %{{.*}}] : memref<?x?xf32, #[[strided2D]]>
// CHECKLOOP-DAG: %[[b:.*]] = load %[[B]][%{{.*}}, %{{.*}}] : memref<?x?xf32, #[[strided2D]]>
// CHECKLOOP-DAG: %[[a:.*]] = load %[[A]][%{{.*}}, %{{.*}}] : memref<?x?xf32>
// CHECKLOOP-DAG: %[[b:.*]] = load %[[B]][%{{.*}}, %{{.*}}] : memref<?x?xf32>
// CHECKLOOP-DAG: %[[inc:.*]] = mulf %[[a]], %[[b]] : f32
// CHECKLOOP-DAG: %[[c:.*]] = load %[[C]][%{{.*}}, %{{.*}}] : memref<?x?xf32, #[[strided2D]]>
// CHECKLOOP-DAG: %[[c:.*]] = load %[[C]][%{{.*}}, %{{.*}}] : memref<?x?xf32>
// CHECKLOOP-DAG: %[[res:.*]] = addf %[[c]], %[[inc]] : f32
// CHECKLOOP: store %[[res]], %[[C]][%{{.*}}, %{{.*}}] : memref<?x?xf32, #[[strided2D]]>
// CHECKLOOP: store %[[res]], %[[C]][%{{.*}}, %{{.*}}] : memref<?x?xf32>
// CHECKPARALLEL-LABEL: func @matmul(%{{.*}}: memref<?xi8>,
// CHECKPARALLEL-SAME: [[M:arg[0-9]+]]: index
// CHECKPARALLEL-SAME: [[N:arg[0-9]+]]: index
// CHECKPARALLEL-SAME: [[K:arg[0-9]+]]: index
// CHECKPARALLEL: %[[A:.*]] = std.view %{{.*}}[{{.*}}] : memref<?xi8> to memref<?x?xf32, #[[strided2D]]>
// CHECKPARALLEL: %[[B:.*]] = std.view %{{.*}}[{{.*}}] : memref<?xi8> to memref<?x?xf32, #[[strided2D]]>
// CHECKPARALLEL: %[[C:.*]] = std.view %{{.*}}[{{.*}}] : memref<?xi8> to memref<?x?xf32, #[[strided2D]]>
// CHECKPARALLEL: %[[A:.*]] = std.view %{{.*}}[{{.*}}] : memref<?xi8> to memref<?x?xf32>
// CHECKPARALLEL: %[[B:.*]] = std.view %{{.*}}[{{.*}}] : memref<?xi8> to memref<?x?xf32>
// CHECKPARALLEL: %[[C:.*]] = std.view %{{.*}}[{{.*}}] : memref<?xi8> to memref<?x?xf32>
// CHECKPARALLEL: loop.parallel (%{{.*}}, %{{.*}}) = (%{{.*}}, %{{.*}}) to (%[[M]], %[[N]]) step (%{{.*}}, %{{.*}} {
// CHECKPARALLEL: loop.for %{{.*}} = %{{.*}} to %[[K]] step %{{.*}} {
// CHECKPARALLEL-DAG: %[[a:.*]] = load %[[A]][%{{.*}}, %{{.*}}] : memref<?x?xf32, #[[strided2D]]>
// CHECKPARALLEL-DAG: %[[b:.*]] = load %[[B]][%{{.*}}, %{{.*}}] : memref<?x?xf32, #[[strided2D]]>
// CHECKPARALLEL-DAG: %[[a:.*]] = load %[[A]][%{{.*}}, %{{.*}}] : memref<?x?xf32>
// CHECKPARALLEL-DAG: %[[b:.*]] = load %[[B]][%{{.*}}, %{{.*}}] : memref<?x?xf32>
// CHECKPARALLEL-DAG: %[[inc:.*]] = mulf %[[a]], %[[b]] : f32
// CHECKPARALLEL-DAG: %[[c:.*]] = load %[[C]][%{{.*}}, %{{.*}}] : memref<?x?xf32, #[[strided2D]]>
// CHECKPARALLEL-DAG: %[[c:.*]] = load %[[C]][%{{.*}}, %{{.*}}] : memref<?x?xf32>
// CHECKPARALLEL-DAG: %[[res:.*]] = addf %[[c]], %[[inc]] : f32
// CHECKPARALLEL: store %[[res]], %[[C]][%{{.*}}, %{{.*}}] : memref<?x?xf32, #[[strided2D]]>
// CHECKPARALLEL: store %[[res]], %[[C]][%{{.*}}, %{{.*}}] : memref<?x?xf32>
func @matvec(%arg0: memref<?xi8>, %M: index, %N: index) {
%c0 = constant 0 : index
%c1 = constant 1 : index
%2 = view %arg0[%c0][%M, %N] : memref<?xi8> to memref<?x?xf32, offset: ?, strides: [?, 1]>
%3 = view %arg0[%c0][%M] : memref<?xi8> to memref<?xf32, offset: ?, strides: [1]>
%4 = view %arg0[%c0][%N] : memref<?xi8> to memref<?xf32, offset: ?, strides: [1]>
linalg.matvec(%2, %3, %4) : memref<?x?xf32, offset: ?, strides: [?, 1]>, memref<?xf32, offset: ?, strides: [1]>, memref<?xf32, offset: ?, strides: [1]>
%2 = view %arg0[%c0][%M, %N] : memref<?xi8> to memref<?x?xf32>
%3 = view %arg0[%c0][%M] : memref<?xi8> to memref<?xf32>
%4 = view %arg0[%c0][%N] : memref<?xi8> to memref<?xf32>
linalg.matvec(%2, %3, %4) : memref<?x?xf32>, memref<?xf32>, memref<?xf32>
return
}
// CHECKLOOP-LABEL: func @matvec(%{{.*}}: memref<?xi8>,
// CHECKLOOP-SAME: [[M:arg[0-9]+]]: index
// CHECKLOOP-SAME: [[K:arg[0-9]+]]: index
// CHECKLOOP: %[[A:.*]] = std.view %{{.*}}[{{.*}}] : memref<?xi8> to memref<?x?xf32, #[[strided2D]]>
// CHECKLOOP: %[[B:.*]] = std.view %{{.*}}[{{.*}}] : memref<?xi8> to memref<?xf32, #[[strided1D]]>
// CHECKLOOP: %[[C:.*]] = std.view %{{.*}}[{{.*}}] : memref<?xi8> to memref<?xf32, #[[strided1D]]>
// CHECKLOOP: %[[A:.*]] = std.view %{{.*}}[{{.*}}] : memref<?xi8> to memref<?x?xf32>
// CHECKLOOP: %[[B:.*]] = std.view %{{.*}}[{{.*}}] : memref<?xi8> to memref<?xf32>
// CHECKLOOP: %[[C:.*]] = std.view %{{.*}}[{{.*}}] : memref<?xi8> to memref<?xf32>
// CHECKLOOP: loop.for %{{.*}} = %{{.*}} to %[[M]] step %{{.*}} {
// CHECKLOOP: loop.for %{{.*}} = %{{.*}} to %[[K]] step %{{.*}} {
// CHECKLOOP-DAG: %[[a:.*]] = load %[[A]][%{{.*}}, %{{.*}}] : memref<?x?xf32, #[[strided2D]]>
// CHECKLOOP-DAG: %[[b:.*]] = load %[[B]][%{{.*}}] : memref<?xf32, #[[strided1D]]>
// CHECKLOOP-DAG: %[[a:.*]] = load %[[A]][%{{.*}}, %{{.*}}] : memref<?x?xf32>
// CHECKLOOP-DAG: %[[b:.*]] = load %[[B]][%{{.*}}] : memref<?xf32>
// CHECKLOOP-DAG: %[[inc:.*]] = mulf %[[a]], %[[b]] : f32
// CHECKLOOP-DAG: %[[c:.*]] = load %[[C]][%{{.*}}] : memref<?xf32, #[[strided1D]]>
// CHECKLOOP-DAG: %[[c:.*]] = load %[[C]][%{{.*}}] : memref<?xf32>
// CHECKLOOP-DAG: %[[res:.*]] = addf %[[c]], %[[inc]] : f32
// CHECKLOOP: store %[[res]], %[[C]][%{{.*}}] : memref<?xf32, #[[strided1D]]>
// CHECKLOOP: store %[[res]], %[[C]][%{{.*}}] : memref<?xf32>
// CHECKPARALLEL-LABEL: func @matvec(%{{.*}}: memref<?xi8>,
// CHECKPARALLEL-SAME: [[M:arg[0-9]+]]: index
// CHECKPARALLEL-SAME: [[K:arg[0-9]+]]: index
// CHECKPARALLEL: %[[A:.*]] = std.view %{{.*}}[{{.*}}] : memref<?xi8> to memref<?x?xf32, #[[strided2D]]>
// CHECKPARALLEL: %[[B:.*]] = std.view %{{.*}}[{{.*}}] : memref<?xi8> to memref<?xf32, #[[strided1D]]>
// CHECKPARALLEL: %[[C:.*]] = std.view %{{.*}}[{{.*}}] : memref<?xi8> to memref<?xf32, #[[strided1D]]>
// CHECKPARALLEL: %[[A:.*]] = std.view %{{.*}}[{{.*}}] : memref<?xi8> to memref<?x?xf32>
// CHECKPARALLEL: %[[B:.*]] = std.view %{{.*}}[{{.*}}] : memref<?xi8> to memref<?xf32>
// CHECKPARALLEL: %[[C:.*]] = std.view %{{.*}}[{{.*}}] : memref<?xi8> to memref<?xf32>
// CHECKPARALLEL: loop.parallel (%{{.*}}) = (%{{.*}}) to (%[[M]]) step (%{{.*}}) {
// CHECKPARALLEL: loop.for %{{.*}} = %{{.*}} to %[[K]] step %{{.*}} {
// CHECKPARALLEL-DAG: %[[a:.*]] = load %[[A]][%{{.*}}, %{{.*}}] : memref<?x?xf32, #[[strided2D]]>
// CHECKPARALLEL-DAG: %[[b:.*]] = load %[[B]][%{{.*}}] : memref<?xf32, #[[strided1D]]>
// CHECKPARALLEL-DAG: %[[a:.*]] = load %[[A]][%{{.*}}, %{{.*}}] : memref<?x?xf32>
// CHECKPARALLEL-DAG: %[[b:.*]] = load %[[B]][%{{.*}}] : memref<?xf32>
// CHECKPARALLEL-DAG: %[[inc:.*]] = mulf %[[a]], %[[b]] : f32
// CHECKPARALLEL-DAG: %[[c:.*]] = load %[[C]][%{{.*}}] : memref<?xf32, #[[strided1D]]>
// CHECKPARALLEL-DAG: %[[c:.*]] = load %[[C]][%{{.*}}] : memref<?xf32>
// CHECKPARALLEL-DAG: %[[res:.*]] = addf %[[c]], %[[inc]] : f32
// CHECKPARALLEL: store %[[res]], %[[C]][%{{.*}}] : memref<?xf32, #[[strided1D]]>
// CHECKPARALLEL: store %[[res]], %[[C]][%{{.*}}] : memref<?xf32>
func @dot(%arg0: memref<?xi8>, %M: index) {
%c0 = constant 0 : index
%c1 = constant 1 : index
%1 = view %arg0[%c0][%M] : memref<?xi8> to memref<?xf32, offset: ?, strides: [1]>
%2 = view %arg0[%c0][%M] : memref<?xi8> to memref<?xf32, offset: ?, strides: [1]>
%3 = view %arg0[][] : memref<?xi8> to memref<f32>
linalg.dot(%1, %2, %3) : memref<?xf32, offset: ?, strides: [1]>, memref<?xf32, offset: ?, strides: [1]>, memref<f32>
%1 = view %arg0[%c0][%M] : memref<?xi8> to memref<?xf32>
%2 = view %arg0[%c0][%M] : memref<?xi8> to memref<?xf32>
%3 = view %arg0[%c0][] : memref<?xi8> to memref<f32>
linalg.dot(%1, %2, %3) : memref<?xf32>, memref<?xf32>, memref<f32>
return
}
// CHECKLOOP-LABEL: func @dot(%{{.*}}: memref<?xi8>,
// CHECKLOOP-SAME: [[K:arg[0-9]+]]: index
// CHECKLOOP: %[[A:.*]] = std.view %{{.*}}[{{.*}}][{{.*}}] : memref<?xi8> to memref<?xf32, #[[strided1D]]>
// CHECKLOOP: %[[B:.*]] = std.view %{{.*}}[{{.*}}][{{.*}}] : memref<?xi8> to memref<?xf32, #[[strided1D]]>
// CHECKLOOP: %[[C:.*]] = std.view %{{.*}}[][] : memref<?xi8> to memref<f32>
// CHECKLOOP: %[[A:.*]] = std.view %{{.*}}[{{.*}}][{{.*}}] : memref<?xi8> to memref<?xf32>
// CHECKLOOP: %[[B:.*]] = std.view %{{.*}}[{{.*}}][{{.*}}] : memref<?xi8> to memref<?xf32>
// CHECKLOOP: %[[C:.*]] = std.view %{{.*}}[{{.*}}][] : memref<?xi8> to memref<f32>
// CHECKLOOP: loop.for %{{.*}} = %{{.*}} to %[[K]] step %{{.*}} {
// CHECKLOOP-DAG: %[[a:.*]] = load %[[A]][%{{.*}}] : memref<?xf32, #[[strided1D]]>
// CHECKLOOP-DAG: %[[b:.*]] = load %[[B]][%{{.*}}] : memref<?xf32, #[[strided1D]]>
// CHECKLOOP-DAG: %[[a:.*]] = load %[[A]][%{{.*}}] : memref<?xf32>
// CHECKLOOP-DAG: %[[b:.*]] = load %[[B]][%{{.*}}] : memref<?xf32>
// CHECKLOOP-DAG: %[[inc:.*]] = mulf %[[a]], %[[b]] : f32
// CHECKLOOP-DAG: %[[c:.*]] = load %[[C]][] : memref<f32>
// CHECKLOOP-DAG: %[[res:.*]] = addf %[[c]], %[[inc]] : f32
@ -135,12 +135,12 @@ func @dot(%arg0: memref<?xi8>, %M: index) {
// CHECKPARALLEL-LABEL: func @dot(%{{.*}}: memref<?xi8>,
// CHECKPARALLEL-SAME: [[K:arg[0-9]+]]: index
// CHECKPARALLEL: %[[A:.*]] = std.view %{{.*}}[{{.*}}][{{.*}}] : memref<?xi8> to memref<?xf32, #[[strided1D]]>
// CHECKPARALLEL: %[[B:.*]] = std.view %{{.*}}[{{.*}}][{{.*}}] : memref<?xi8> to memref<?xf32, #[[strided1D]]>
// CHECKPARALLEL: %[[C:.*]] = std.view %{{.*}}[][] : memref<?xi8> to memref<f32>
// CHECKPARALLEL: %[[A:.*]] = std.view %{{.*}}[{{.*}}][{{.*}}] : memref<?xi8> to memref<?xf32>
// CHECKPARALLEL: %[[B:.*]] = std.view %{{.*}}[{{.*}}][{{.*}}] : memref<?xi8> to memref<?xf32>
// CHECKPARALLEL: %[[C:.*]] = std.view %{{.*}}[{{.*}}][] : memref<?xi8> to memref<f32>
// CHECKPARALLEL: loop.for %{{.*}} = %{{.*}} to %[[K]] step %{{.*}} {
// CHECKPARALLEL-DAG: %[[a:.*]] = load %[[A]][%{{.*}}] : memref<?xf32, #[[strided1D]]>
// CHECKPARALLEL-DAG: %[[b:.*]] = load %[[B]][%{{.*}}] : memref<?xf32, #[[strided1D]]>
// CHECKPARALLEL-DAG: %[[a:.*]] = load %[[A]][%{{.*}}] : memref<?xf32>
// CHECKPARALLEL-DAG: %[[b:.*]] = load %[[B]][%{{.*}}] : memref<?xf32>
// CHECKPARALLEL-DAG: %[[inc:.*]] = mulf %[[a]], %[[b]] : f32
// CHECKPARALLEL-DAG: %[[c:.*]] = load %[[C]][] : memref<f32>
// CHECKPARALLEL-DAG: %[[res:.*]] = addf %[[c]], %[[inc]] : f32

View File

@ -1,7 +1,6 @@
// RUN: mlir-opt %s -linalg-promote-subviews | FileCheck %s
// RUN: mlir-opt %s -linalg-promote-subviews="test-promote-dynamic" | FileCheck %s --check-prefix=DYNAMIC
#map0 = affine_map<(d0, d1)[s0, s1] -> (d0 * s1 + s0 + d1)>
#map1 = affine_map<(d0) -> (d0 + 2)>
#map2 = affine_map<(d0) -> (d0 + 4)>
#map3 = affine_map<(d0) -> (d0 + 3)>
@ -15,19 +14,19 @@ func @matmul_f32(%A: memref<?xi8>, %M: index, %N: index, %K: index) {
%c2 = constant 2 : index
%c0 = constant 0 : index
%c1 = constant 1 : index
%3 = view %A[%c0][%M, %K] : memref<?xi8> to memref<?x?xf32, #map0>
%4 = view %A[%c0][%K, %N] : memref<?xi8> to memref<?x?xf32, #map0>
%5 = view %A[%c0][%M, %N] : memref<?xi8> to memref<?x?xf32, #map0>
%6 = dim %3, 0 : memref<?x?xf32, #map0>
%7 = dim %3, 1 : memref<?x?xf32, #map0>
%8 = dim %4, 1 : memref<?x?xf32, #map0>
%3 = view %A[%c0][%M, %K] : memref<?xi8> to memref<?x?xf32>
%4 = view %A[%c0][%K, %N] : memref<?xi8> to memref<?x?xf32>
%5 = view %A[%c0][%M, %N] : memref<?xi8> to memref<?x?xf32>
%6 = dim %3, 0 : memref<?x?xf32>
%7 = dim %3, 1 : memref<?x?xf32>
%8 = dim %4, 1 : memref<?x?xf32>
loop.for %arg4 = %c0 to %6 step %c2 {
loop.for %arg5 = %c0 to %8 step %c3 {
loop.for %arg6 = %c0 to %7 step %c4 {
%11 = std.subview %3[%arg4, %arg6][%c2, %c4][%c1, %c1] : memref<?x?xf32, #map0> to memref<?x?xf32, offset: ?, strides: [?, ?]>
%14 = std.subview %4[%arg6, %arg5][%c4, %c3][%c1, %c1] : memref<?x?xf32, #map0> to memref<?x?xf32, offset: ?, strides: [?, ?]>
%17 = std.subview %5[%arg4, %arg5][%c2, %c3][%c1, %c1] : memref<?x?xf32, #map0> to memref<?x?xf32, offset: ?, strides: [?, ?]>
linalg.matmul(%11, %14, %17) : memref<?x?xf32, offset: ?, strides: [?, ?]>, memref<?x?xf32, offset: ?, strides: [?, ?]>, memref<?x?xf32, offset: ?, strides: [?, ?]>
%11 = std.subview %3[%arg4, %arg6][%c2, %c4][] : memref<?x?xf32> to memref<?x?xf32, offset: ?, strides: [?, 1]>
%14 = std.subview %4[%arg6, %arg5][%c4, %c3][] : memref<?x?xf32> to memref<?x?xf32, offset: ?, strides: [?, 1]>
%17 = std.subview %5[%arg4, %arg5][%c2, %c3][] : memref<?x?xf32> to memref<?x?xf32, offset: ?, strides: [?, 1]>
linalg.matmul(%11, %14, %17) : memref<?x?xf32, offset: ?, strides: [?, 1]>, memref<?x?xf32, offset: ?, strides: [?, 1]>, memref<?x?xf32, offset: ?, strides: [?, 1]>
}
}
}
@ -38,35 +37,35 @@ func @matmul_f32(%A: memref<?xi8>, %M: index, %N: index, %K: index) {
// CHECK: loop.for %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} {
// CHECK: loop.for %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} {
// CHECK: loop.for %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} {
// CHECK: %[[vA:.*]] = subview {{.*}} : memref<?x?xf32, #[[strided2D]]>
// CHECK: %[[vB:.*]] = subview {{.*}} : memref<?x?xf32, #[[strided2D]]>
// CHECK: %[[vC:.*]] = subview {{.*}} : memref<?x?xf32, #[[strided2D]]>
// CHECK: %[[vA:.*]] = subview {{.*}} : memref<?x?xf32>
// CHECK: %[[vB:.*]] = subview {{.*}} : memref<?x?xf32>
// CHECK: %[[vC:.*]] = subview {{.*}} : memref<?x?xf32>
///
// CHECK: %[[tmpA:.*]] = alloc() : memref<32xi8>
// CHECK: %[[fullA:.*]] = std.view %[[tmpA]][][{{.*}}] : memref<32xi8> to memref<?x?xf32>
// DYNAMIC: std.view %{{.*}}[][{{.*}}] : memref<?xi8> to memref<?x?xf32>
// CHECK: %[[fullA:.*]] = std.view %[[tmpA]][{{.*}}][{{.*}}] : memref<32xi8> to memref<?x?xf32>
// DYNAMIC: std.view %{{.*}}[{{.*}}][{{.*}}] : memref<?xi8> to memref<?x?xf32>
// CHECK: %[[partialA:.*]] = subview %[[fullA]]{{.*}} : memref<?x?xf32> to memref<?x?xf32, #[[strided2D_dynamic]]>
///
// CHECK: %[[tmpB:.*]] = alloc() : memref<48xi8>
// CHECK: %[[fullB:.*]] = std.view %[[tmpB]][][{{.*}}] : memref<48xi8> to memref<?x?xf32>
// DYNAMIC: std.view %{{.*}}[][{{.*}}] : memref<?xi8> to memref<?x?xf32>
// CHECK: %[[fullB:.*]] = std.view %[[tmpB]][{{.*}}][{{.*}}] : memref<48xi8> to memref<?x?xf32>
// DYNAMIC: std.view %{{.*}}[{{.*}}][{{.*}}] : memref<?xi8> to memref<?x?xf32>
// CHECK: %[[partialB:.*]] = subview %[[fullB]]{{.*}} : memref<?x?xf32> to memref<?x?xf32, #[[strided2D_dynamic]]>
///
// CHECK: %[[tmpC:.*]] = alloc() : memref<24xi8>
// CHECK: %[[fullC:.*]] = std.view %[[tmpC]][][{{.*}}] : memref<24xi8> to memref<?x?xf32>
// DYNAMIC: std.view %{{.*}}[][{{.*}}] : memref<?xi8> to memref<?x?xf32>
// CHECK: %[[fullC:.*]] = std.view %[[tmpC]][{{.*}}][{{.*}}] : memref<24xi8> to memref<?x?xf32>
// DYNAMIC: std.view %{{.*}}[{{.*}}][{{.*}}] : memref<?xi8> to memref<?x?xf32>
// CHECK: %[[partialC:.*]] = subview %[[fullC]]{{.*}} : memref<?x?xf32> to memref<?x?xf32, #[[strided2D_dynamic]]>
// CHECK: linalg.fill(%[[fullA]], {{.*}}) : memref<?x?xf32>, f32
// CHECK: linalg.fill(%[[fullB]], {{.*}}) : memref<?x?xf32>, f32
// CHECK: linalg.fill(%[[fullC]], {{.*}}) : memref<?x?xf32>, f32
// CHECK: linalg.copy(%[[vA]], %[[partialA]]) : memref<?x?xf32, #[[strided2D_dynamic]]>, memref<?x?xf32, #[[strided2D_dynamic]]>
// CHECK: linalg.copy(%[[vB]], %[[partialB]]) : memref<?x?xf32, #[[strided2D_dynamic]]>, memref<?x?xf32, #[[strided2D_dynamic]]>
// CHECK: linalg.copy(%[[vC]], %[[partialC]]) : memref<?x?xf32, #[[strided2D_dynamic]]>, memref<?x?xf32, #[[strided2D_dynamic]]>
// CHECK: linalg.copy(%[[vA]], %[[partialA]]) : memref<?x?xf32, #[[strided2D]]>, memref<?x?xf32, #[[strided2D_dynamic]]>
// CHECK: linalg.copy(%[[vB]], %[[partialB]]) : memref<?x?xf32, #[[strided2D]]>, memref<?x?xf32, #[[strided2D_dynamic]]>
// CHECK: linalg.copy(%[[vC]], %[[partialC]]) : memref<?x?xf32, #[[strided2D]]>, memref<?x?xf32, #[[strided2D_dynamic]]>
//
// CHECK: linalg.matmul(%[[fullA]], %[[fullB]], %[[fullC]]) : memref<?x?xf32>, memref<?x?xf32>, memref<?x?xf32>
//
// CHECK: linalg.copy(%[[partialC]], %[[vC]]) : memref<?x?xf32, #[[strided2D_dynamic]]>, memref<?x?xf32, #[[strided2D_dynamic]]>
// CHECK: linalg.copy(%[[partialC]], %[[vC]]) : memref<?x?xf32, #[[strided2D_dynamic]]>, memref<?x?xf32, #[[strided2D]]>
//
// CHECK: dealloc %[[tmpA]] : memref<32xi8>
// CHECK: dealloc %[[tmpB]] : memref<48xi8>
@ -80,19 +79,19 @@ func @matmul_f64(%A: memref<?xi8>, %M: index, %N: index, %K: index) {
%c2 = constant 2 : index
%c0 = constant 0 : index
%c1 = constant 1 : index
%3 = view %A[%c0][%M, %K] : memref<?xi8> to memref<?x?xf64, #map0>
%4 = view %A[%c0][%K, %N] : memref<?xi8> to memref<?x?xf64, #map0>
%5 = view %A[%c0][%M, %N] : memref<?xi8> to memref<?x?xf64, #map0>
%6 = dim %3, 0 : memref<?x?xf64, #map0>
%7 = dim %3, 1 : memref<?x?xf64, #map0>
%8 = dim %4, 1 : memref<?x?xf64, #map0>
%3 = view %A[%c0][%M, %K] : memref<?xi8> to memref<?x?xf64>
%4 = view %A[%c0][%K, %N] : memref<?xi8> to memref<?x?xf64>
%5 = view %A[%c0][%M, %N] : memref<?xi8> to memref<?x?xf64>
%6 = dim %3, 0 : memref<?x?xf64>
%7 = dim %3, 1 : memref<?x?xf64>
%8 = dim %4, 1 : memref<?x?xf64>
loop.for %arg4 = %c0 to %6 step %c2 {
loop.for %arg5 = %c0 to %8 step %c3 {
loop.for %arg6 = %c0 to %7 step %c4 {
%11 = std.subview %3[%arg4, %arg6][%c2, %c4][%c1, %c1] : memref<?x?xf64, #map0> to memref<?x?xf64, offset: ?, strides: [?, ?]>
%14 = std.subview %4[%arg6, %arg5][%c4, %c3][%c1, %c1] : memref<?x?xf64, #map0> to memref<?x?xf64, offset: ?, strides: [?, ?]>
%17 = std.subview %5[%arg4, %arg5][%c2, %c3][%c1, %c1] : memref<?x?xf64, #map0> to memref<?x?xf64, offset: ?, strides: [?, ?]>
linalg.matmul(%11, %14, %17) : memref<?x?xf64, offset: ?, strides: [?, ?]>, memref<?x?xf64, offset: ?, strides: [?, ?]>, memref<?x?xf64, offset: ?, strides: [?, ?]>
%11 = std.subview %3[%arg4, %arg6][%c2, %c4][] : memref<?x?xf64> to memref<?x?xf64, offset: ?, strides: [?, 1]>
%14 = std.subview %4[%arg6, %arg5][%c4, %c3][] : memref<?x?xf64> to memref<?x?xf64, offset: ?, strides: [?, 1]>
%17 = std.subview %5[%arg4, %arg5][%c2, %c3][] : memref<?x?xf64> to memref<?x?xf64, offset: ?, strides: [?, 1]>
linalg.matmul(%11, %14, %17) : memref<?x?xf64, offset: ?, strides: [?, 1]>, memref<?x?xf64, offset: ?, strides: [?, 1]>, memref<?x?xf64, offset: ?, strides: [?, 1]>
}
}
}
@ -103,35 +102,35 @@ func @matmul_f64(%A: memref<?xi8>, %M: index, %N: index, %K: index) {
// CHECK: loop.for %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} {
// CHECK: loop.for %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} {
// CHECK: loop.for %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} {
// CHECK: %[[vA_f64:.*]] = subview {{.*}} : memref<?x?xf64, #[[strided2D]]>
// CHECK: %[[vB_f64:.*]] = subview {{.*}} : memref<?x?xf64, #[[strided2D]]>
// CHECK: %[[vC_f64:.*]] = subview {{.*}} : memref<?x?xf64, #[[strided2D]]>
// CHECK: %[[vA_f64:.*]] = subview {{.*}} : memref<?x?xf64>
// CHECK: %[[vB_f64:.*]] = subview {{.*}} : memref<?x?xf64>
// CHECK: %[[vC_f64:.*]] = subview {{.*}} : memref<?x?xf64>
///
// CHECK: %[[tmpA_f64:.*]] = alloc() : memref<64xi8>
// CHECK: %[[fullA_f64:.*]] = std.view %[[tmpA_f64]][][{{.*}}] : memref<64xi8> to memref<?x?xf64>
// DYNAMIC: std.view %{{.*}}[][{{.*}}] : memref<?xi8> to memref<?x?xf64>
// CHECK: %[[fullA_f64:.*]] = std.view %[[tmpA_f64]][{{.*}}][{{.*}}] : memref<64xi8> to memref<?x?xf64>
// DYNAMIC: std.view %{{.*}}[{{.*}}][{{.*}}] : memref<?xi8> to memref<?x?xf64>
// CHECK: %[[partialA_f64:.*]] = subview %[[fullA_f64]][%{{.*}}, %{{.*}}] : memref<?x?xf64> to memref<?x?xf64, #[[strided2D_dynamic]]>
///
// CHECK: %[[tmpB_f64:.*]] = alloc() : memref<96xi8>
// CHECK: %[[fullB_f64:.*]] = std.view %[[tmpB_f64]][][{{.*}}] : memref<96xi8> to memref<?x?xf64>
// DYNAMIC: std.view %{{.*}}[][{{.*}}] : memref<?xi8> to memref<?x?xf64>
// CHECK: %[[fullB_f64:.*]] = std.view %[[tmpB_f64]][{{.*}}][{{.*}}] : memref<96xi8> to memref<?x?xf64>
// DYNAMIC: std.view %{{.*}}[{{.*}}][{{.*}}] : memref<?xi8> to memref<?x?xf64>
// CHECK: %[[partialB_f64:.*]] = subview %[[fullB_f64]][%{{.*}}, %{{.*}}] : memref<?x?xf64> to memref<?x?xf64, #[[strided2D_dynamic]]>
///
// CHECK: %[[tmpC_f64:.*]] = alloc() : memref<48xi8>
// CHECK: %[[fullC_f64:.*]] = std.view %[[tmpC_f64]][][{{.*}}] : memref<48xi8> to memref<?x?xf64>
// DYNAMIC: std.view %{{.*}}[][{{.*}}] : memref<?xi8> to memref<?x?xf64>
// CHECK: %[[fullC_f64:.*]] = std.view %[[tmpC_f64]][{{.*}}][{{.*}}] : memref<48xi8> to memref<?x?xf64>
// DYNAMIC: std.view %{{.*}}[{{.*}}][{{.*}}] : memref<?xi8> to memref<?x?xf64>
// CHECK: %[[partialC_f64:.*]] = subview %[[fullC_f64]][%{{.*}}, %{{.*}}] : memref<?x?xf64> to memref<?x?xf64, #[[strided2D_dynamic]]>
// CHECK: linalg.fill(%[[fullA_f64]], {{.*}}) : memref<?x?xf64>, f64
// CHECK: linalg.fill(%[[fullB_f64]], {{.*}}) : memref<?x?xf64>, f64
// CHECK: linalg.fill(%[[fullC_f64]], {{.*}}) : memref<?x?xf64>, f64
// CHECK: linalg.copy(%[[vA_f64]], %[[partialA_f64]]) : memref<?x?xf64, #[[strided2D_dynamic]]>, memref<?x?xf64, #[[strided2D_dynamic]]>
// CHECK: linalg.copy(%[[vB_f64]], %[[partialB_f64]]) : memref<?x?xf64, #[[strided2D_dynamic]]>, memref<?x?xf64, #[[strided2D_dynamic]]>
// CHECK: linalg.copy(%[[vC_f64]], %[[partialC_f64]]) : memref<?x?xf64, #[[strided2D_dynamic]]>, memref<?x?xf64, #[[strided2D_dynamic]]>
// CHECK: linalg.copy(%[[vA_f64]], %[[partialA_f64]]) : memref<?x?xf64, #[[strided2D]]>, memref<?x?xf64, #[[strided2D_dynamic]]>
// CHECK: linalg.copy(%[[vB_f64]], %[[partialB_f64]]) : memref<?x?xf64, #[[strided2D]]>, memref<?x?xf64, #[[strided2D_dynamic]]>
// CHECK: linalg.copy(%[[vC_f64]], %[[partialC_f64]]) : memref<?x?xf64, #[[strided2D]]>, memref<?x?xf64, #[[strided2D_dynamic]]>
//
// CHECK: linalg.matmul(%[[fullA_f64]], %[[fullB_f64]], %[[fullC_f64]]) : memref<?x?xf64>, memref<?x?xf64>, memref<?x?xf64>
//
// CHECK: linalg.copy(%[[partialC_f64]], %[[vC_f64]]) : memref<?x?xf64, #[[strided2D_dynamic]]>, memref<?x?xf64, #[[strided2D_dynamic]]>
// CHECK: linalg.copy(%[[partialC_f64]], %[[vC_f64]]) : memref<?x?xf64, #[[strided2D_dynamic]]>, memref<?x?xf64, #[[strided2D]]>
//
// CHECK: dealloc %[[tmpA_f64]] : memref<64xi8>
// CHECK: dealloc %[[tmpB_f64]] : memref<96xi8>
@ -145,19 +144,19 @@ func @matmul_i32(%A: memref<?xi8>, %M: index, %N: index, %K: index) {
%c2 = constant 2 : index
%c0 = constant 0 : index
%c1 = constant 1 : index
%3 = view %A[%c0][%M, %K] : memref<?xi8> to memref<?x?xi32, #map0>
%4 = view %A[%c0][%K, %N] : memref<?xi8> to memref<?x?xi32, #map0>
%5 = view %A[%c0][%M, %N] : memref<?xi8> to memref<?x?xi32, #map0>
%6 = dim %3, 0 : memref<?x?xi32, #map0>
%7 = dim %3, 1 : memref<?x?xi32, #map0>
%8 = dim %4, 1 : memref<?x?xi32, #map0>
%3 = view %A[%c0][%M, %K] : memref<?xi8> to memref<?x?xi32>
%4 = view %A[%c0][%K, %N] : memref<?xi8> to memref<?x?xi32>
%5 = view %A[%c0][%M, %N] : memref<?xi8> to memref<?x?xi32>
%6 = dim %3, 0 : memref<?x?xi32>
%7 = dim %3, 1 : memref<?x?xi32>
%8 = dim %4, 1 : memref<?x?xi32>
loop.for %arg4 = %c0 to %6 step %c2 {
loop.for %arg5 = %c0 to %8 step %c3 {
loop.for %arg6 = %c0 to %7 step %c4 {
%11 = std.subview %3[%arg4, %arg6][%c2, %c4][%c1, %c1] : memref<?x?xi32, #map0> to memref<?x?xi32, offset: ?, strides: [?, ?]>
%14 = std.subview %4[%arg6, %arg5][%c4, %c3][%c1, %c1] : memref<?x?xi32, #map0> to memref<?x?xi32, offset: ?, strides: [?, ?]>
%17 = std.subview %5[%arg4, %arg5][%c2, %c3][%c1, %c1] : memref<?x?xi32, #map0> to memref<?x?xi32, offset: ?, strides: [?, ?]>
linalg.matmul(%11, %14, %17) : memref<?x?xi32, offset: ?, strides: [?, ?]>, memref<?x?xi32, offset: ?, strides: [?, ?]>, memref<?x?xi32, offset: ?, strides: [?, ?]>
%11 = std.subview %3[%arg4, %arg6][%c2, %c4][] : memref<?x?xi32> to memref<?x?xi32, offset: ?, strides: [?, 1]>
%14 = std.subview %4[%arg6, %arg5][%c4, %c3][] : memref<?x?xi32> to memref<?x?xi32, offset: ?, strides: [?, 1]>
%17 = std.subview %5[%arg4, %arg5][%c2, %c3][] : memref<?x?xi32> to memref<?x?xi32, offset: ?, strides: [?, 1]>
linalg.matmul(%11, %14, %17) : memref<?x?xi32, offset: ?, strides: [?, 1]>, memref<?x?xi32, offset: ?, strides: [?, 1]>, memref<?x?xi32, offset: ?, strides: [?, 1]>
}
}
}
@ -168,35 +167,35 @@ func @matmul_i32(%A: memref<?xi8>, %M: index, %N: index, %K: index) {
// CHECK: loop.for %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} {
// CHECK: loop.for %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} {
// CHECK: loop.for %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} {
// CHECK: %[[vA_i32:.*]] = subview {{.*}} : memref<?x?xi32, #[[strided2D]]>
// CHECK: %[[vB_i32:.*]] = subview {{.*}} : memref<?x?xi32, #[[strided2D]]>
// CHECK: %[[vC_i32:.*]] = subview {{.*}} : memref<?x?xi32, #[[strided2D]]>
// CHECK: %[[vA_i32:.*]] = subview {{.*}} : memref<?x?xi32>
// CHECK: %[[vB_i32:.*]] = subview {{.*}} : memref<?x?xi32>
// CHECK: %[[vC_i32:.*]] = subview {{.*}} : memref<?x?xi32>
///
// CHECK: %[[tmpA_i32:.*]] = alloc() : memref<32xi8>
// CHECK: %[[fullA_i32:.*]] = std.view %[[tmpA_i32]][][{{.*}}] : memref<32xi8> to memref<?x?xi32>
// DYNAMIC: std.view %{{.*}}[][{{.*}}] : memref<?xi8> to memref<?x?xi32>
// CHECK: %[[fullA_i32:.*]] = std.view %[[tmpA_i32]][{{.*}}][{{.*}}] : memref<32xi8> to memref<?x?xi32>
// DYNAMIC: std.view %{{.*}}[{{.*}}][{{.*}}] : memref<?xi8> to memref<?x?xi32>
// CHECK: %[[partialA_i32:.*]] = subview %[[fullA_i32]][%{{.*}}, %{{.*}}] : memref<?x?xi32> to memref<?x?xi32, #[[strided2D_dynamic]]>
///
// CHECK: %[[tmpB_i32:.*]] = alloc() : memref<48xi8>
// CHECK: %[[fullB_i32:.*]] = std.view %[[tmpB_i32]][][{{.*}}] : memref<48xi8> to memref<?x?xi32>
// DYNAMIC: std.view %{{.*}}[][{{.*}}] : memref<?xi8> to memref<?x?xi32>
// CHECK: %[[fullB_i32:.*]] = std.view %[[tmpB_i32]][{{.*}}][{{.*}}] : memref<48xi8> to memref<?x?xi32>
// DYNAMIC: std.view %{{.*}}[{{.*}}][{{.*}}] : memref<?xi8> to memref<?x?xi32>
// CHECK: %[[partialB_i32:.*]] = subview %[[fullB_i32]][%{{.*}}, %{{.*}}] : memref<?x?xi32> to memref<?x?xi32, #[[strided2D_dynamic]]>
///
// CHECK: %[[tmpC_i32:.*]] = alloc() : memref<24xi8>
// CHECK: %[[fullC_i32:.*]] = std.view %[[tmpC_i32]][][{{.*}}] : memref<24xi8> to memref<?x?xi32>
// DYNAMIC: std.view %{{.*}}[][{{.*}}] : memref<?xi8> to memref<?x?xi32>
// CHECK: %[[fullC_i32:.*]] = std.view %[[tmpC_i32]][{{.*}}][{{.*}}] : memref<24xi8> to memref<?x?xi32>
// DYNAMIC: std.view %{{.*}}[{{.*}}][{{.*}}] : memref<?xi8> to memref<?x?xi32>
// CHECK: %[[partialC_i32:.*]] = subview %[[fullC_i32]][%{{.*}}, %{{.*}}] : memref<?x?xi32> to memref<?x?xi32, #[[strided2D_dynamic]]>
// CHECK: linalg.fill(%[[fullA_i32]], {{.*}}) : memref<?x?xi32>, i32
// CHECK: linalg.fill(%[[fullB_i32]], {{.*}}) : memref<?x?xi32>, i32
// CHECK: linalg.fill(%[[fullC_i32]], {{.*}}) : memref<?x?xi32>, i32
// CHECK: linalg.copy(%[[vA_i32]], %[[partialA_i32]]) : memref<?x?xi32, #[[strided2D_dynamic]]>, memref<?x?xi32, #[[strided2D_dynamic]]>
// CHECK: linalg.copy(%[[vB_i32]], %[[partialB_i32]]) : memref<?x?xi32, #[[strided2D_dynamic]]>, memref<?x?xi32, #[[strided2D_dynamic]]>
// CHECK: linalg.copy(%[[vC_i32]], %[[partialC_i32]]) : memref<?x?xi32, #[[strided2D_dynamic]]>, memref<?x?xi32, #[[strided2D_dynamic]]>
// CHECK: linalg.copy(%[[vA_i32]], %[[partialA_i32]]) : memref<?x?xi32, #[[strided2D]]>, memref<?x?xi32, #[[strided2D_dynamic]]>
// CHECK: linalg.copy(%[[vB_i32]], %[[partialB_i32]]) : memref<?x?xi32, #[[strided2D]]>, memref<?x?xi32, #[[strided2D_dynamic]]>
// CHECK: linalg.copy(%[[vC_i32]], %[[partialC_i32]]) : memref<?x?xi32, #[[strided2D]]>, memref<?x?xi32, #[[strided2D_dynamic]]>
//
// CHECK: linalg.matmul(%[[fullA_i32]], %[[fullB_i32]], %[[fullC_i32]]) : memref<?x?xi32>, memref<?x?xi32>, memref<?x?xi32>
//
// CHECK: linalg.copy(%[[partialC_i32]], %[[vC_i32]]) : memref<?x?xi32, #[[strided2D_dynamic]]>, memref<?x?xi32, #[[strided2D_dynamic]]>
// CHECK: linalg.copy(%[[partialC_i32]], %[[vC_i32]]) : memref<?x?xi32, #[[strided2D_dynamic]]>, memref<?x?xi32, #[[strided2D]]>
//
// CHECK: dealloc %[[tmpA_i32]] : memref<32xi8>
// CHECK: dealloc %[[tmpB_i32]] : memref<48xi8>

View File

@ -16,34 +16,31 @@ func @range(%arg0: index, %arg1: index, %arg2: index) {
// -----
// CHECK-DAG: #[[strided1D:.*]] = affine_map<(d0)[s0] -> (d0 + s0)>
// CHECK-DAG: #[[strided2D:.*]] = affine_map<(d0, d1)[s0, s1] -> (d0 * s1 + s0 + d1)>
func @views(%arg0: index, %arg1: index, %arg2: index, %arg3: index, %arg4: index) {
%c0 = constant 0 : index
%0 = muli %arg0, %arg0 : index
%1 = alloc (%0) : memref<?xi8>
%2 = linalg.range %arg0:%arg1:%arg2 : !linalg.range
%3 = view %1[%c0][%arg0, %arg0] :
memref<?xi8> to memref<?x?xf32, offset: ?, strides: [?, 1]>
%3 = view %1[%c0][%arg0, %arg0] : memref<?xi8> to memref<?x?xf32>
%4 = linalg.slice %3[%2, %2] :
memref<?x?xf32, offset: ?, strides: [?, 1]>,
memref<?x?xf32>,
!linalg.range,
!linalg.range,
memref<?x?xf32, offset: ?, strides: [?, 1]>
%5 = linalg.slice %3[%2, %arg2] : memref<?x?xf32, offset: ?, strides: [?, 1]>,
memref<?x?xf32>
%5 = linalg.slice %3[%2, %arg2] : memref<?x?xf32>,
!linalg.range,
index,
memref<?xf32, offset: ?, strides: [1]>
%6 = linalg.slice %3[%arg2, %2] : memref<?x?xf32, offset: ?, strides: [?, 1]>,
%6 = linalg.slice %3[%arg2, %2] : memref<?x?xf32>,
index,
!linalg.range,
memref<?xf32, offset: ?, strides: [1]>
%7 = linalg.slice %3[%arg2, %arg3] : memref<?x?xf32, offset: ?, strides: [?, 1]>,
%7 = linalg.slice %3[%arg2, %arg3] : memref<?x?xf32>,
index,
index,
memref<f32>
%8 = view %1[%c0][%arg0, %arg0] :
memref<?xi8> to memref<?x?xvector<4x4xf32>, offset: ?, strides: [?, 1]>
%8 = view %1[%c0][%arg0, %arg0] : memref<?xi8> to memref<?x?xvector<4x4xf32>>
dealloc %1 : memref<?xi8>
return
}
@ -52,29 +49,29 @@ func @views(%arg0: index, %arg1: index, %arg2: index, %arg3: index, %arg4: index
// CHECK-NEXT: alloc(%{{.*}}) : memref<?xi8>
// CHECK-NEXT: range
// CHECK-NEXT: std.view %{{.*}}[%{{.*}}][%{{.*}}] :
// CHECK-SAME: memref<?xi8> to memref<?x?xf32, #[[strided2D]]>
// CHECK-SAME: memref<?xi8> to memref<?x?xf32>
// CHECK-NEXT: linalg.slice %{{.*}}[%{{.*}}, %{{.*}}] :
// CHECK-SAME: memref<?x?xf32, #[[strided2D]]>,
// CHECK-SAME: memref<?x?xf32>,
// CHECK-SAME: !linalg.range,
// CHECK-SAME: !linalg.range,
// CHECK-SAME: memref<?x?xf32, #[[strided2D]]>
// CHECK-SAME: memref<?x?xf32>
// CHECK-NEXT: linalg.slice %{{.*}}[%{{.*}}, %{{.*}}] :
// CHECK-SAME: memref<?x?xf32, #[[strided2D]]>,
// CHECK-SAME: memref<?x?xf32>,
// CHECK-SAME: !linalg.range,
// CHECK-SAME: index,
// CHECK-SAME: memref<?xf32, #[[strided1D]]>
// CHECK-NEXT: linalg.slice %{{.*}}[%{{.*}}, %{{.*}}] :
// CHECK-SAME: memref<?x?xf32, #[[strided2D]]>,
// CHECK-SAME: memref<?x?xf32>,
// CHECK-SAME: index,
// CHECK-SAME: !linalg.range,
// CHECK-SAME: memref<?xf32, #[[strided1D]]>
// CHECK-NEXT: linalg.slice %{{.*}}[%{{.*}}, %{{.*}}] :
// CHECK-SAME: memref<?x?xf32, #[[strided2D]]>,
// CHECK-SAME: memref<?x?xf32>,
// CHECK-SAME: index,
// CHECK-SAME: index,
// CHECK-SAME: memref<f32>
// CHECK-NEXT: view %{{.*}}[%{{.*}}][%{{.*}}] :
// CHECK-SAME: memref<?xi8> to memref<?x?xvector<4x4xf32>, #[[strided2D]]>
// CHECK-SAME: memref<?xi8> to memref<?x?xvector<4x4xf32>>
// CHECK-NEXT: dealloc %{{.*}} : memref<?xi8>
// -----

View File

@ -280,13 +280,13 @@ func @promote_subview_matmul(%arg0: memref<?x?xf32, offset: ?, strides: [?, 1]>,
// CHECK: %[[s1:.*]] = subview {{%.*}}[{{%.*}}, {{%.*}}] [{{%.*}}, {{%.*}}] [{{%.*}}, {{%.*}}] : memref<?x?xf32, #map{{.*}}> to memref<?x?xf32, #map{{.*}}>
// CHECK: %[[s2:.*]] = subview {{%.*}}[{{%.*}}, {{%.*}}] [{{%.*}}, {{%.*}}] [{{%.*}}, {{%.*}}] : memref<?x?xf32, #map{{.*}}> to memref<?x?xf32, #map{{.*}}>
// CHECK: %[[a0:.*]] = alloc({{%.*}}) : memref<?xi8>
// CHECK: %[[v0:.*]] = std.view %[[a0]][][{{%.*}}, {{%.*}}] : memref<?xi8> to memref<?x?xf32>
// CHECK: %[[v0:.*]] = std.view %[[a0]][{{.*}}][{{%.*}}, {{%.*}}] : memref<?xi8> to memref<?x?xf32>
// CHECK: %[[l0:.*]] = subview %[[v0]][{{%.*}}, {{%.*}}] [{{%.*}}, {{%.*}}] : memref<?x?xf32> to memref<?x?xf32, #[[STRIDED_2D]]>
// CHECK: %[[a1:.*]] = alloc({{%.*}}) : memref<?xi8>
// CHECK: %[[v1:.*]] = std.view %[[a1]][][{{%.*}}, {{%.*}}] : memref<?xi8> to memref<?x?xf32>
// CHECK: %[[v1:.*]] = std.view %[[a1]][{{.*}}][{{%.*}}, {{%.*}}] : memref<?xi8> to memref<?x?xf32>
// CHECK: %[[l1:.*]] = subview %[[v1]][{{%.*}}, {{%.*}}] [{{%.*}}, {{%.*}}] : memref<?x?xf32> to memref<?x?xf32, #[[STRIDED_2D]]>
// CHECK: %[[a2:.*]] = alloc({{%.*}}) : memref<?xi8>
// CHECK: %[[v2:.*]] = std.view %[[a2]][][{{%.*}}, {{%.*}}] : memref<?xi8> to memref<?x?xf32>
// CHECK: %[[v2:.*]] = std.view %[[a2]][{{.*}}][{{%.*}}, {{%.*}}] : memref<?xi8> to memref<?x?xf32>
// CHECK: %[[l2:.*]] = subview %[[v2]][{{%.*}}, {{%.*}}] [{{%.*}}, {{%.*}}] : memref<?x?xf32> to memref<?x?xf32, #[[STRIDED_2D]]>
// CHECK: linalg.copy(%[[s0]], %[[l0]]) : memref<?x?xf32, #map{{.*}}>, memref<?x?xf32, #map{{.*}}>
// CHECK: linalg.copy(%[[s1]], %[[l1]]) : memref<?x?xf32, #map{{.*}}>, memref<?x?xf32, #map{{.*}}>
@ -330,13 +330,13 @@ func @promote_first_subview_matmul(%arg0: memref<?x?xf32, offset: ?, strides: [?
// CHECK: %[[s1:.*]] = subview {{%.*}}[{{%.*}}, {{%.*}}] [{{%.*}}, {{%.*}}] [{{%.*}}, {{%.*}}] : memref<?x?xf32, #map{{.*}}> to memref<?x?xf32, #map{{.*}}>
// CHECK: %[[s2:.*]] = subview {{%.*}}[{{%.*}}, {{%.*}}] [{{%.*}}, {{%.*}}] [{{%.*}}, {{%.*}}] : memref<?x?xf32, #map{{.*}}> to memref<?x?xf32, #map{{.*}}>
// CHECK: %[[a0:.*]] = alloc({{%.*}}) : memref<?xi8>
// CHECK: %[[v0:.*]] = std.view %[[a0]][][{{%.*}}, {{%.*}}] : memref<?xi8> to memref<?x?xf32>
// CHECK: %[[v0:.*]] = std.view %[[a0]][{{.*}}][{{%.*}}, {{%.*}}] : memref<?xi8> to memref<?x?xf32>
// CHECK: %[[l0:.*]] = subview %[[v0]][{{%.*}}, {{%.*}}] [{{%.*}}, {{%.*}}] [{{%.*}}, {{%.*}}] : memref<?x?xf32> to memref<?x?xf32, #[[STRIDED_2D]]>
// CHECK-NOT: %[[a1:.*]] = alloc({{%.*}}) : memref<?xi8>
// CHECK-NOT: %[[v1:.*]] = std.view %[[a1]][][{{%.*}}, {{%.*}}] : memref<?xi8> to memref<?x?xf32>
// CHECK-NOT: %[[v1:.*]] = std.view %[[a1]][{{.*}}][{{%.*}}, {{%.*}}] : memref<?xi8> to memref<?x?xf32>
// CHECK-NOT: %[[l0:.*]] = subview %[[v1]][{{%.*}}, {{%.*}}] [{{%.*}}, {{%.*}}] [{{%.*}}, {{%.*}}] : memref<?x?xf32> to memref<?x?xf32, #[[STRIDED_2D]]>
// CHECK-NOT: %[[a2:.*]] = alloc({{%.*}}) : memref<?xi8>
// CHECK-NOT: %[[v2:.*]] = std.view %[[a2]][][{{%.*}}, {{%.*}}] : memref<?xi8> to memref<?x?xf32>
// CHECK-NOT: %[[v2:.*]] = std.view %[[a2]][{{.*}}][{{%.*}}, {{%.*}}] : memref<?xi8> to memref<?x?xf32>
// CHECK-NOT: %[[l0:.*]] = subview %[[v2]][{{%.*}}, {{%.*}}] [{{%.*}}, {{%.*}}] [{{%.*}}, {{%.*}}] : memref<?x?xf32> to memref<?x?xf32, #[[STRIDED_2D]]>
// CHECK: linalg.copy(%[[s0]], %[[l0]]) : memref<?x?xf32, #map{{.*}}>, memref<?x?xf32, #map{{.*}}>
// CHECK-NOT: linalg.copy(%[[s1]], %[[l1]]) : memref<?x?xf32, #map{{.*}}>, memref<?x?xf32, #map{{.*}}>
@ -359,7 +359,7 @@ func @aligned_promote_fill(%arg0: memref<?x?xf32, offset: ?, strides: [?, 1]>) {
// CHECK: %[[cf:.*]] = constant {{.*}} : f32
// CHECK: %[[s0:.*]] = subview {{%.*}}[{{%.*}}, {{%.*}}] [{{%.*}}, {{%.*}}] [{{%.*}}, {{%.*}}] : memref<?x?xf32, #map{{.*}}> to memref<?x?xf32, #map{{.*}}>
// CHECK: %[[a0:.*]] = alloc({{%.*}}) {alignment = 32 : i64} : memref<?xi8>
// CHECK: %[[v0:.*]] = std.view %[[a0]][][{{%.*}}, {{%.*}}] : memref<?xi8> to memref<?x?xf32>
// CHECK: %[[v0:.*]] = std.view %[[a0]][{{.*}}][{{%.*}}, {{%.*}}] : memref<?xi8> to memref<?x?xf32>
// CHECK: %[[l0:.*]] = subview %[[v0]][{{%.*}}, {{%.*}}] [{{%.*}}, {{%.*}}] : memref<?x?xf32> to memref<?x?xf32, #[[STRIDED_2D]]>
// CHECK: linalg.fill(%[[v0]], {{%.*}}) : memref<?x?xf32>, f32
// CHECK: linalg.copy(%[[s0]], %[[l0]]) : memref<?x?xf32, #map{{.*}}>, memref<?x?xf32, #map{{.*}}>

View File

@ -8,10 +8,6 @@
// CHECK: #map1 = affine_map<()[s0] -> (s0 + 1)>
// CHECK-DAG: #[[VIEW_MAP1:map[0-9]+]] = affine_map<(d0, d1) -> (d0 * 4 + d1)>
// CHECK-DAG: #[[VIEW_MAP2:map[0-9]+]] = affine_map<(d0, d1)[s0, s1] -> (d0 * s1 + d1 + s0)>
// CHECK-DAG: #[[VIEW_MAP3:map[0-9]+]] = affine_map<(d0, d1)[s0] -> (d0 * s0 + d1)>
// CHECK-DAG: #[[BASE_MAP0:map[0-9]+]] = affine_map<(d0, d1, d2) -> (d0 * 64 + d1 * 4 + d2)>
// CHECK-DAG: #[[BASE_MAP3:map[0-9]+]] = affine_map<(d0, d1, d2)[s0, s1, s2, s3] -> (d0 * s1 + s0 + d1 * s2 + d2 * s3)>
// CHECK-DAG: #[[SUBVIEW_MAP0:map[0-9]+]] = affine_map<(d0, d1, d2)[s0, s1, s2, s3] -> (d0 * s1 + d1 * s2 + d2 * s3 + s0)>
@ -692,29 +688,17 @@ func @memref_cast(%arg0: memref<4xf32>, %arg1 : memref<?xf32>, %arg2 : memref<64
func @memref_view(%arg0 : index, %arg1 : index, %arg2 : index) {
%0 = alloc() : memref<2048xi8>
// Test two dynamic sizes and dynamic offset.
// CHECK: %{{.*}} = std.view %0[%arg2][%arg0, %arg1] : memref<2048xi8> to memref<?x?xf32, #[[VIEW_MAP2]]>
%1 = view %0[%arg2][%arg0, %arg1]
: memref<2048xi8> to memref<?x?xf32, affine_map<(d0, d1)[s0, s1] -> (d0 * s1 + d1 + s0)>>
// Test two dynamic sizes and static offset.
// CHECK: %{{.*}} = std.view %0[][%arg0, %arg1] : memref<2048xi8> to memref<?x?xf32, #[[VIEW_MAP3]]>
%2 = view %0[][%arg0, %arg1]
: memref<2048xi8> to memref<?x?xf32, affine_map<(d0, d1)[s0] -> (d0 * s0 + d1)>>
// CHECK: %{{.*}} = std.view %0[%arg2][%arg0, %arg1] : memref<2048xi8> to memref<?x?xf32>
%1 = view %0[%arg2][%arg0, %arg1] : memref<2048xi8> to memref<?x?xf32>
// Test one dynamic size and dynamic offset.
// CHECK: %{{.*}} = std.view %0[%arg2][%arg1] : memref<2048xi8> to memref<4x?xf32, #[[VIEW_MAP2]]>
%3 = view %0[%arg2][%arg1]
: memref<2048xi8> to memref<4x?xf32, affine_map<(d0, d1)[s0, s1] -> (d0 * s1 + d1 + s0)>>
// Test one dynamic size and static offset.
// CHECK: %{{.*}} = std.view %0[][%arg0] : memref<2048xi8> to memref<?x4xf32, #[[VIEW_MAP1]]>
%4 = view %0[][%arg0]
: memref<2048xi8> to memref<?x4xf32, affine_map<(d0, d1) -> (d0 * 4 + d1)>>
// CHECK: %{{.*}} = std.view %0[%arg2][%arg1] : memref<2048xi8> to memref<4x?xf32>
%3 = view %0[%arg2][%arg1] : memref<2048xi8> to memref<4x?xf32>
// Test static sizes and static offset.
// CHECK: %{{.*}} = std.view %0[][] : memref<2048xi8> to memref<64x4xf32, #[[VIEW_MAP1]]>
%5 = view %0[][]
: memref<2048xi8> to memref<64x4xf32, affine_map<(d0, d1) -> (d0 * 4 + d1)>>
// CHECK: %{{.*}} = std.view %0[{{.*}}][] : memref<2048xi8> to memref<64x4xf32>
%c0 = constant 0: index
%5 = view %0[%c0][] : memref<2048xi8> to memref<64x4xf32>
return
}

View File

@ -927,29 +927,9 @@ func @invalid_splat(%v : f32) { // expected-note {{prior use here}}
func @invalid_view(%arg0 : index, %arg1 : index, %arg2 : index) {
%0 = alloc() : memref<2048xi8>
// expected-error@+1 {{incorrect number of operands for type}}
// expected-error@+1 {{expects 1 offset operand}}
%1 = view %0[][%arg0, %arg1]
: memref<2048xi8> to memref<?x?xf32, affine_map<(d0, d1)[s0] -> (d0 * 4 + d1 + s0)>>
return
}
// -----
func @invalid_view(%arg0 : index, %arg1 : index, %arg2 : index) {
%0 = alloc() : memref<2048xi8>
// expected-error@+1 {{is not strided}}
%1 = view %0[][%arg0, %arg1]
: memref<2048xi8> to memref<?x?xf32, affine_map<(d0, d1)[s0] -> (d0, d1, s0)>>
return
}
// -----
func @invalid_view(%arg0 : index, %arg1 : index, %arg2 : index) {
%0 = alloc() : memref<2048xf32>
// expected-error@+1 {{must be 1D memref of 8-bit signless integer values}}
%1 = view %0[][%arg0, %arg1]
: memref<2048xf32> to memref<?x?xf32, affine_map<(d0, d1)[s0] -> (d0 * 4 + d1 + s0)>>
: memref<2048xi8> to memref<?x?xf32>
return
}
@ -957,8 +937,8 @@ func @invalid_view(%arg0 : index, %arg1 : index, %arg2 : index) {
func @invalid_view(%arg0 : index, %arg1 : index, %arg2 : index) {
%0 = alloc() : memref<2048xi8, affine_map<(d0) -> (d0 floordiv 8, d0 mod 8)>>
// expected-error@+1 {{unsupported map for base memref}}
%1 = view %0[][%arg0, %arg1]
// expected-error@+1 {{unsupported map for base memref type}}
%1 = view %0[%arg2][%arg0, %arg1]
: memref<2048xi8, affine_map<(d0) -> (d0 floordiv 8, d0 mod 8)>> to
memref<?x?xf32, affine_map<(d0, d1)[s0] -> (d0 * 4 + d1 + s0)>>
return
@ -966,12 +946,20 @@ func @invalid_view(%arg0 : index, %arg1 : index, %arg2 : index) {
// -----
func @invalid_view(%arg0 : index, %arg1 : index, %arg2 : index) {
%0 = alloc() : memref<2048xi8>
// expected-error@+1 {{unsupported map for result memref type}}
%1 = view %0[%arg2][%arg0, %arg1]
: memref<2048xi8> to memref<?x?xf32, affine_map<(d0, d1)[s0] -> (d0, d1, s0)>>
return
}
// -----
func @invalid_view(%arg0 : index, %arg1 : index, %arg2 : index) {
%0 = alloc() : memref<2048xi8, 2>
// expected-error@+1 {{different memory spaces}}
%1 = view %0[][%arg0, %arg1]
: memref<2048xi8, 2> to
memref<?x?xf32, affine_map<(d0, d1)[s0] -> (d0 * 4 + d1 + s0)>, 1>
%1 = view %0[%arg2][%arg0, %arg1] : memref<2048xi8, 2> to memref<?x?xf32, 1>
return
}
@ -979,32 +967,9 @@ func @invalid_view(%arg0 : index, %arg1 : index, %arg2 : index) {
func @invalid_view(%arg0 : index, %arg1 : index, %arg2 : index) {
%0 = alloc() : memref<2048xi8>
// expected-error@+1 {{incorrect dynamic strides}}
%1 = view %0[][%arg0, %arg1]
: memref<2048xi8> to
memref<?x?x4xf32, affine_map<(d0, d1, d2) -> (d0 * 777 + d1 * 4 + d2)>>
return
}
// -----
func @invalid_view(%arg0 : index, %arg1 : index, %arg2 : index) {
%0 = alloc() : memref<2048xi8>
// expected-error@+1 {{incorrect dynamic strides}}
%1 = view %0[%arg0][]
: memref<2048xi8> to
memref<16x4x?xf32, affine_map<(d0, d1, d2) -> (d0 * 777 + d1 * 4 + d2)>>
return
}
// -----
func @multiple_offsets(%arg0: index) {
%0 = alloc() : memref<2048xi8>
// expected-error@+1 {{expects 0 or 1 offset operand}}
%1 = view %0[%arg0, %arg0][%arg0]
: memref<2048xi8> to
memref<?x?x4xf32, affine_map<(d0, d1, d2) -> (d0 * 777 + d1 * 4 + d2)>>
// expected-error@+1 {{incorrect number of size operands for type}}
%1 = view %0[%arg2][%arg0]
: memref<2048xi8> to memref<?x?xf32>
return
}

View File

@ -445,9 +445,9 @@ func @dim_op_fold(%arg0: index, %arg1: index, %arg2: index, %BUF: memref<?xi8>,
%ub = dim %3, 0 : memref<?xi8>
affine.for %arg4 = 0 to %ub {
%s = dim %0, 0 : memref<?x?xf32>
%v = std.view %3[%c0][%arg4, %s] : memref<?xi8> to memref<?x?xf32, #map1>
%v = std.view %3[%c0][%arg4, %s] : memref<?xi8> to memref<?x?xf32>
%sv = subview %0[%c0, %c0][%s,%arg4][%c1,%c1] : memref<?x?xf32> to memref<?x?xf32, #map1>
%l = dim %v, 1 : memref<?x?xf32, #map1>
%l = dim %v, 1 : memref<?x?xf32>
%u = dim %sv, 0 : memref<?x?xf32, #map1>
affine.for %arg5 = %l to %u {
"foo"() : () -> ()
@ -462,13 +462,13 @@ func @dim_op_fold(%arg0: index, %arg1: index, %arg2: index, %BUF: memref<?xi8>,
// CHECK-NEXT: }
// CHECK-NEXT: }
%A = view %BUF[%c0][%M, %K] : memref<?xi8> to memref<?x?xf32, offset: ?, strides: [?, 1]>
%B = view %BUF[%c0][%K, %N] : memref<?xi8> to memref<?x?xf32, offset: ?, strides: [?, 1]>
%C = view %BUF[%c0][%M, %N] : memref<?xi8> to memref<?x?xf32, offset: ?, strides: [?, 1]>
%A = view %BUF[%c0][%M, %K] : memref<?xi8> to memref<?x?xf32>
%B = view %BUF[%c0][%K, %N] : memref<?xi8> to memref<?x?xf32>
%C = view %BUF[%c0][%M, %N] : memref<?xi8> to memref<?x?xf32>
%M_ = dim %A, 0 : memref<?x?xf32, offset: ?, strides: [?, 1]>
%K_ = dim %A, 1 : memref<?x?xf32, offset: ?, strides: [?, 1]>
%N_ = dim %C, 1 : memref<?x?xf32, offset: ?, strides: [?, 1]>
%M_ = dim %A, 0 : memref<?x?xf32>
%K_ = dim %A, 1 : memref<?x?xf32>
%N_ = dim %C, 1 : memref<?x?xf32>
loop.for %i = %c0 to %M_ step %c1 {
loop.for %j = %c0 to %N_ step %c1 {
loop.for %k = %c0 to %K_ step %c1 {
@ -642,19 +642,9 @@ func @cast_values(%arg0: tensor<*xi32>, %arg1: memref<?xi32>) -> (tensor<2xi32>,
// -----
#TEST_VIEW_MAP0 = affine_map<(d0, d1)[s0, s1] -> (d0 * s1 + d1 + s0)>
#TEST_VIEW_MAP1 = affine_map<(d0, d1, d2)[s0, s1] -> (d0 * s1 + d1 * s0 + d2)>
#TEST_VIEW_MAP2 = affine_map<(d0, d1)[s0] -> (d0 * 4 + d1 + s0)>
// CHECK-DAG: #[[VIEW_MAP0:map[0-9]+]] = affine_map<(d0, d1) -> (d0 * 11 + d1 + 15)>
// CHECK-DAG: #[[VIEW_MAP1:map[0-9]+]] = affine_map<(d0, d1)[s0] -> (d0 * 11 + s0 + d1)>
// CHECK-DAG: #[[VIEW_MAP2:map[0-9]+]] = affine_map<(d0, d1)[s0] -> (d0 * s0 + d1 + 15)>
// CHECK-DAG: #[[VIEW_MAP3:map[0-9]+]] = affine_map<(d0, d1, d2)[s0] -> (d0 * s0 + d1 * 7 + d2)>
// CHECK-DAG: #[[VIEW_MAP4:map[0-9]+]] = affine_map<(d0, d1) -> (d0 * 4 + d1 + 15)>
// CHECK-DAG: #[[VIEW_MAP5:map[0-9]+]] = affine_map<(d0, d1) -> (d0 * 7 + d1)>
// CHECK-LABEL: func @view
func @view(%arg0 : index) -> (f32, f32, f32, f32, f32, f32) {
func @view(%arg0 : index) -> (f32, f32, f32, f32) {
// CHECK: %[[C15:.*]] = constant 15 : index
// CHECK: %[[ALLOC_MEM:.*]] = alloc() : memref<2048xi8>
%0 = alloc() : memref<2048xi8>
%c0 = constant 0 : index
@ -662,45 +652,27 @@ func @view(%arg0 : index) -> (f32, f32, f32, f32, f32, f32) {
%c11 = constant 11 : index
%c15 = constant 15 : index
// Test: fold constant sizes and offset, update map with static stride/offset.
// CHECK: std.view %[[ALLOC_MEM]][][] : memref<2048xi8> to memref<7x11xf32, #[[VIEW_MAP0]]>
%1 = view %0[%c15][%c7, %c11]
: memref<2048xi8> to memref<?x?xf32, #TEST_VIEW_MAP0>
%r0 = load %1[%c0, %c0] : memref<?x?xf32, #TEST_VIEW_MAP0>
// Test: fold constant sizes.
// CHECK: std.view %[[ALLOC_MEM]][%[[C15]]][] : memref<2048xi8> to memref<7x11xf32>
%1 = view %0[%c15][%c7, %c11] : memref<2048xi8> to memref<?x?xf32>
%r0 = load %1[%c0, %c0] : memref<?x?xf32>
// Test: fold constant sizes but not offset, update map with static stride.
// Test that we do not a fold dynamic dim which is not produced by a constant.
// CHECK: std.view %[[ALLOC_MEM]][%arg0][] : memref<2048xi8> to memref<7x11xf32, #[[VIEW_MAP1]]>
%2 = view %0[%arg0][%c7, %c11]
: memref<2048xi8> to memref<?x?xf32, #TEST_VIEW_MAP0>
%r1 = load %2[%c0, %c0] : memref<?x?xf32, #TEST_VIEW_MAP0>
// Test: fold one constant size.
// CHECK: std.view %[[ALLOC_MEM]][%[[C15]]][%arg0, %arg0] : memref<2048xi8> to memref<?x?x7xf32>
%2 = view %0[%c15][%arg0, %arg0, %c7] : memref<2048xi8> to memref<?x?x?xf32>
%r1 = load %2[%c0, %c0, %c0] : memref<?x?x?xf32>
// Test: fold constant offset but not sizes, update map with constant offset.
// Test that we fold constant offset but not dynamic dims.
// CHECK: std.view %[[ALLOC_MEM]][][%arg0, %arg0] : memref<2048xi8> to memref<?x?xf32, #[[VIEW_MAP2]]>
%3 = view %0[%c15][%arg0, %arg0]
: memref<2048xi8> to memref<?x?xf32, #TEST_VIEW_MAP0>
%r2 = load %3[%c0, %c0] : memref<?x?xf32, #TEST_VIEW_MAP0>
// Test: fold one constant dim, no offset, should update with constant
// stride on dim 1, but leave dynamic stride on dim 0.
// CHECK: std.view %[[ALLOC_MEM]][][%arg0, %arg0] : memref<2048xi8> to memref<?x?x7xf32, #[[VIEW_MAP3]]>
%4 = view %0[][%arg0, %arg0, %c7]
: memref<2048xi8> to memref<?x?x?xf32, #TEST_VIEW_MAP1>
%r3 = load %4[%c0, %c0, %c0] : memref<?x?x?xf32, #TEST_VIEW_MAP1>
// Test: preserve an existing static dim size while folding a dynamic
// dimension and offset.
// CHECK: std.view %[[ALLOC_MEM]][][] : memref<2048xi8> to memref<7x4xf32, #[[VIEW_MAP4]]>
%5 = view %0[%c15][%c7] : memref<2048xi8> to memref<?x4xf32, #TEST_VIEW_MAP2>
%r4 = load %5[%c0, %c0] : memref<?x4xf32, #TEST_VIEW_MAP2>
// Test: preserve an existing static size.
// CHECK: std.view %[[ALLOC_MEM]][%[[C15]]][] : memref<2048xi8> to memref<7x4xf32>
%3 = view %0[%c15][%c7] : memref<2048xi8> to memref<?x4xf32>
%r2 = load %3[%c0, %c0] : memref<?x4xf32>
// Test: folding static alloc and memref_cast into a view.
// CHECK: std.view %[[ALLOC_MEM]][][] : memref<2048xi8> to memref<15x7xf32, #[[VIEW_MAP5]]>
%6 = memref_cast %0 : memref<2048xi8> to memref<?xi8>
%7 = view %6[%c15][%c7] : memref<?xi8> to memref<?x?xf32>
%r5 = load %7[%c0, %c0] : memref<?x?xf32>
return %r0, %r1, %r2, %r3, %r4, %r5 : f32, f32, f32, f32, f32, f32
// CHECK: std.view %[[ALLOC_MEM]][%[[C15]]][] : memref<2048xi8> to memref<15x7xf32>
%4 = memref_cast %0 : memref<2048xi8> to memref<?xi8>
%5 = view %4[%c15][%c15, %c7] : memref<?xi8> to memref<?x?xf32>
%r3 = load %5[%c0, %c0] : memref<?x?xf32>
return %r0, %r1, %r2, %r3 : f32, f32, f32, f32
}
// -----

View File

@ -22,9 +22,6 @@
// RUN: | mlir-cpu-runner -e matmul -entry-point-result=f32 -shared-libs=%linalg_test_lib_dir/libmlir_test_cblas%shlibext,%linalg_test_lib_dir/libmlir_test_cblas_interface%shlibext \
// RUN: | FileCheck %s
#strided1D = affine_map<(d0) -> (d0)>
#strided2D = affine_map<(d0, d1)[s0] -> (d0 * s0 + d1)>
// Creates and returns a 1-D buffer of size %s filled with the value %f
func @alloc_filled_f32(%s : index, %f : f32) -> memref<?xi8> {
%c0 = constant 0 : index
@ -32,8 +29,8 @@ func @alloc_filled_f32(%s : index, %f : f32) -> memref<?xi8> {
%c4 = constant 4 : index
%s4 = muli %s, %c4: index
%buf = alloc(%s4) {alignment = 256} : memref<?xi8>
%V = view %buf[%s][] : memref<?xi8> to memref<?xf32, #strided1D>
linalg.fill(%V, %f) : memref<?xf32, #strided1D>, f32
%V = view %buf[%c0][%s] : memref<?xi8> to memref<?xf32>
linalg.fill(%V, %f) : memref<?xf32>, f32
return %buf : memref<?xi8>
}
@ -50,11 +47,11 @@ func @dot() -> f32 {
%bB = call @alloc_filled_f32(%c16, %f1) : (index, f32) -> (memref<?xi8>)
%bC = call @alloc_filled_f32(%c1, %f10) : (index, f32) -> (memref<?xi8>)
%A = view %bA[%c16][] : memref<?xi8> to memref<?xf32, #strided1D>
%B = view %bB[%c16][] : memref<?xi8> to memref<?xf32, #strided1D>
%C = view %bC[][] : memref<?xi8> to memref<f32>
%A = view %bA[%c0][%c16] : memref<?xi8> to memref<?xf32>
%B = view %bB[%c0][%c16] : memref<?xi8> to memref<?xf32>
%C = view %bC[%c0][] : memref<?xi8> to memref<f32>
linalg.dot(%A, %B, %C) : memref<?xf32, #strided1D>, memref<?xf32, #strided1D>, memref<f32>
linalg.dot(%A, %B, %C) : memref<?xf32>, memref<?xf32>, memref<f32>
%res = load %C[] : memref<f32>
dealloc %bC : memref<?xi8>
@ -82,12 +79,12 @@ func @matmul() -> f32 {
%bB = call @alloc_filled_f32(%c160, %f1) : (index, f32) -> (memref<?xi8>)
%bC = call @alloc_filled_f32(%c100, %f10) : (index, f32) -> (memref<?xi8>)
%A = view %bA[][%c10, %c16] : memref<?xi8> to memref<?x?xf32, #strided2D>
%B = view %bB[][%c16, %c10] : memref<?xi8> to memref<?x?xf32, #strided2D>
%C = view %bC[][%c10, %c10] : memref<?xi8> to memref<?x?xf32, #strided2D>
%A = view %bA[%c0][%c10, %c16] : memref<?xi8> to memref<?x?xf32>
%B = view %bB[%c0][%c16, %c10] : memref<?xi8> to memref<?x?xf32>
%C = view %bC[%c0][%c10, %c10] : memref<?xi8> to memref<?x?xf32>
linalg.matmul(%A, %B, %C) : memref<?x?xf32, #strided2D>, memref<?x?xf32, #strided2D>, memref<?x?xf32, #strided2D>
%res = load %C[%c6, %c7] : memref<?x?xf32, #strided2D>
linalg.matmul(%A, %B, %C) : memref<?x?xf32>, memref<?x?xf32>, memref<?x?xf32>
%res = load %C[%c6, %c7] : memref<?x?xf32>
dealloc %bC : memref<?xi8>
dealloc %bB : memref<?xi8>