more generally at interface points across language boundaries (e.g. C++ /
Python).
- Generally, Linalg passes non-owning pointers to View data structures to
- precompiled library calls linked externally.
+ Generally, Linalg passes non-owning pointers to strided memref data
+ structures to precompiled library calls linked externally. The name `view`
+ is used interchangeably in Linalg to signify strided memref.
}];
}
def LinalgIsRangeTypePred : CPred<"$_self.isa<RangeType>()">;
def Range : Type<LinalgIsRangeTypePred, "range">;
-// Whether a type is a ViewType.
-def LinalgIsViewTypePred : CPred<"$_self.isa<ViewType>()">;
-def View : Type<LinalgIsViewTypePred, "view">;
-
#endif // LINALG_BASE
LinalgParametricIntNativeOpTrait<"NLoopTypes", [n_par, n_red, n_win]>
{}
-// The linalg `ViewRanks` trait the API for ops that are known to have a
-// specified list of view ranks.
-// See Linalg/LinalgTraits.h for implementation details an usage.
-class ViewRanks<list<int> ranks> :
-LinalgParametricIntNativeOpTrait<"ViewRanks", ranks>
-{}
-
def ViewTraits : NativeOpTrait<"linalg::ViewTraits">;
// The linalg 'LinalgLibraryInterface' provides access to the 'LinalgOp'
// interface.
def LinalgLibraryInterface : OpInterface<"LinalgOp"> {
let methods = [
- /// Query the number of inputs and outputs from the operation.
InterfaceMethod<
"Query the number of inputs from the current operation.",
"unsigned", "getNumInputs"
"Query the input and output operands from the current operation.",
"Operation::operand_range", "getInputsAndOutputs"
>,
-
- /// Query the number of each type of loop.
InterfaceMethod<
"Query the number of parallel loops within the current operation.",
"unsigned", "getNumParallelLoops"
return op.getNumParallelLoops() + op.getNumReductionLoops() +
op.getNumWindowLoops();
}]>,
-
- /// Get a specific input/output at the given index.
- InterfaceMethod<"Query the input for the given index.",
+ InterfaceMethod<"Query the input view at the given index.",
"Value *", "getInput", (ins "unsigned":$i)
>,
- InterfaceMethod<"Query the output for the given index.",
+ InterfaceMethod<"Query the output view at the given index.",
"Value *", "getOutput", (ins "unsigned":$i)
>,
-
- /// Get the index of the given value, or None if the value is not an input.
InterfaceMethod<[{
Query the index of the given input value, or `None` if the value is not
an input.
}],
"llvm::Optional<unsigned>", "getIndexOfOutput", (ins "Value *":$view)
>,
+ InterfaceMethod<[{
+ Query the type of the input view at the given index.
+ }], "MemRefType", "getInputViewType", (ins "unsigned":$i)>,
+ InterfaceMethod<[{
+ Query the type of the output view at the given index.
+ }], "MemRefType", "getOutputViewType", (ins "unsigned":$i)>,
- /// Get the view type of the input/output at the given index.
- InterfaceMethod<"Query the view type for the given input.",
- "ViewType", "getInputViewType", (ins "unsigned":$i)
- >,
- InterfaceMethod<"Query the view type for the given output.",
- "ViewType", "getOutputViewType", (ins "unsigned":$i)
- >,
-
- /// Create an operation with the given location and operands.
StaticInterfaceMethod<[{
Create an operation of the current type with the given location,
operands, and attributes.
Copies the data in the input view into the output view.
Usage:
- linalg.copy(%arg0, %arg1) : !linalg.view<?xf32>, !linalg.view<?xf32>
+ linalg.copy(%arg0, %arg1) : memref<?xf32, stride_specification>,
+ memref<?xf32, stride_specification>
One possible lowering to loop form is:
%0 = linalg.dim %arg0, 0 : index
loop.for %i0 = %c0 to %0 step %c1 {
- %1 = linalg.load %arg0[%i0] : !linalg.view<?xf32>
- linalg.store %1, %arg1[%i0] : !linalg.view<?xf32>
+ %1 = linalg.load %arg0[%i0] : memref<?xf32, stride_specification>
+ linalg.store %1, %arg1[%i0] : memref<?xf32, stride_specification>
}
Optionally, can take `input_permutation` and `output_permutation` attributes
Usage:
linalg.copy(%arg0, %arg1) {inputPermutation : (i, j, k) -> (i, k, j),
outputPermutation : (i, j, k) -> (k, j, i)} :
- !linalg.view<?x?x?xf32>, !linalg.view<?x?x?xf32>
+ memref<?x?x?xf32, stride_specification>,
+ memref<?x?x?xf32, stride_specification>
One possible lowering to loop form is:
%0 = linalg.dim %arg0, 0
loop.for %i0 = %c0 to %{{.*}} step %c1 {
loop.for %i1 = %c0 to %{{.*}} step %c1 {
loop.for %i2 = %c0 to %{{.*}} step %c1 {
- %3 = linalg.load %arg0[%i0, %i2, %i1] : !linalg.view<?x?x?xf32>
- linalg.store %3, %arg1[%i2, %i1, %i0] : !linalg.view<?x?x?xf32>
+ %3 = linalg.load %arg0[%i0, %i2, %i1] :
+ memref<?x?x?xf32, stride_specification>
+ linalg.store %3, %arg1[%i2, %i1, %i0] :
+ memref<?x?x?xf32, stride_specification>
The views are expected to be compatible for correctness but this is not
enforced at the moment.
}];
let arguments = (ins
- View:$input,
- View:$output,
+ AnyStridedMemRef:$input,
+ AnyStridedMemRef:$output,
OptionalAttr<AffineMapAttr>:$inputPermutation,
OptionalAttr<AffineMapAttr>:$outputPermutation);
// TODO(ntv) this should go away once the usage of OptionalAttr triggers
let extraClassDeclaration = libraryCallName # [{
unsigned getNumParallelLoops() {
auto *view = *(getOperands().begin());
- return view->getType().cast<ViewType>().getRank();
+ return view->getType().cast<MemRefType>().getRank();
}
unsigned getNumReductionLoops() { return 0; }
unsigned getNumWindowLoops() { return 0; }
}
def FillOp : LinalgLibrary_Op<"fill", [NInputsAndOutputs<0, 1>]> {
- let arguments = (ins View, AnyTypeOf<[AnyFloat, AnyInteger, AnyVector]>);
+ let arguments = (ins AnyStridedMemRef,
+ AnyTypeOf<[AnyFloat, AnyInteger, AnyVector]>);
let extraClassDeclaration = libraryCallName # [{
unsigned getNumParallelLoops() {
auto *view = *(getOperands().begin());
- return view->getType().cast<ViewType>().getRank();
+ return view->getType().cast<MemRefType>().getRank();
}
unsigned getNumReductionLoops() { return 0; }
unsigned getNumWindowLoops() { return 0; }
def DotOp : LinalgLibrary_Op<"dot",
[NInputsAndOutputs<2, 1>,
- NLoopTypes<0, 1, 0>,
- ViewRanks<[1, 1, 0]>]> {
- let arguments = (ins View, View, View);
+ NLoopTypes<0, 1, 0>]> {
+ let arguments = (ins AnyStridedMemRefOfRank<1>,
+ AnyStridedMemRefOfRank<1>,
+ AnyStridedMemRefOfRank<0>);
let extraClassDeclaration = libraryCallName;
}
def MatvecOp : LinalgLibrary_Op<"matvec",
[NInputsAndOutputs<2, 1>,
- NLoopTypes<1, 1, 0>,
- ViewRanks<[2, 1, 1]>]> {
- let arguments = (ins View, View, View);
+ NLoopTypes<1, 1, 0>]> {
+ let arguments = (ins AnyStridedMemRefOfRank<2>,
+ AnyStridedMemRefOfRank<1>,
+ AnyStridedMemRefOfRank<1>);
let extraClassDeclaration = libraryCallName;
}
def MatmulOp : LinalgLibrary_Op<"matmul",
[NInputsAndOutputs<2, 1>,
- NLoopTypes<2, 1, 0>,
- ViewRanks<[2, 2, 2]>]> {
- let arguments = (ins View, View, View);
+ NLoopTypes<2, 1, 0>]> {
+ let arguments = (ins AnyStridedMemRefOfRank<2>,
+ AnyStridedMemRefOfRank<2>,
+ AnyStridedMemRefOfRank<2>);
let extraClassDeclaration = libraryCallName;
}
// TODO(ntv) padding.
// Following the TF source of truth above, strides and dilations are integer
// attributes of the same rank as the number of window dimensions.
- let arguments = (ins View:$filter, View:$input, View:$output,
+ let arguments = (ins AnyStridedMemRef:$filter, AnyStridedMemRef:$input,
+ AnyStridedMemRef:$output,
OptionalAttr<I64ArrayAttr>:$strides,
OptionalAttr<I64ArrayAttr>:$dilations);
let extraClassDeclaration = libraryCallName # [{
```
linalg.generic #trait_attribute %A, %B, %C {other-attributes} :
- !linalg.view<?x?xf32>, !linalg.view<?x?xf32>, !linalg.view<?x?xf32>
+ memref<?x?xf32, stride_specification>,
+ memref<?x?xf32, stride_specification>,
+ memref<?x?xf32, stride_specification>
```
Where #trait_attributes is an alias of a dictionary attribute containing:
And can be reused in multiple places as:
```
linalg.generic #matmul_trait %A, %B, %C [other-attributes] :
- !linalg.view<?x?xf32>, !linalg.view<?x?xf32>, !linalg.view<?x?xf32>
+ memref<?x?xf32, stride_specification>,
+ memref<?x?xf32, stride_specification>,
+ memref<?x?xf32, stride_specification>
```
This may lower to either:
```
call @linalg_matmul(%A, %B, %C) :
- (!linalg.view<?x?xf32>, !linalg.view<?x?xf32>, !linalg.view<?x?xf32>)
+ (memref<?x?xf32, stride_specification>,
+ memref<?x?xf32, stride_specification>,
+ memref<?x?xf32, stride_specification>)
-> ()
```
loop.for %m = %c0 to %M step %c1 {
loop.for %n = %c0 to %N step %c1 {
loop.for %k = %c0 to %K step %c1 {
- %a = linalg.load %A[%m, %k] : !linalg.view<?x?xf32>
- %b = linalg.load %B[%k, %n] : !linalg.view<?x?xf32>
- %c = linalg.load %C[%m, %n] : !linalg.view<?x?xf32>
+ %a = linalg.load %A[%m, %k] : memref<?x?xf32, stride_specification>
+ %b = linalg.load %B[%k, %n] : memref<?x?xf32, stride_specification>
+ %c = linalg.load %C[%m, %n] : memref<?x?xf32, stride_specification>
%d = call @mac(%a, %b, %c) : (f32, f32, f32) -> (f32)
- linalg.store %d, %C[%m, %n] : !linalg.view<?x?x?xf32>
+ linalg.store %d, %C[%m, %n] : memref<?x?x?xf32, stride_specification>
}
}
}
```
}];
- let arguments = (ins Variadic<View>:$views,
+ let arguments = (ins Variadic<AnyStridedMemRef>:$views,
AffineMapArrayAttr:$indexing_maps,
I64ArrayAttr:$n_loop_types,
I64ArrayAttr:$n_views,
///
/// Examples:
///
-/// 1. linalg.fill(%A, %f) : !linalg.view<f32>, f32
+/// 1. linalg.fill(%A, %f) : memref<f32>, f32
/// name mangles into `linalg_fill_viewf32_f32_impl`
///
/// 2. linalg.dot(%A, %B, %C) :
-/// !linalg.view<?xf32>, !linalg.view<?xf32>, !linalg.view<f32>
+/// memref<?xf32, stride_specification>,
+/// memref<?xf32, stride_specification>, memref<f32>
/// name mangles into `linalg_dot_viewxf32_viewxf32_viewf32_impl`
///
/// 3. linalg.matmul(...) :
-/// !linalg.view<?x?xf32>, !linalg.view<?x?xf32>, !linalg.view<?x?xf32>
+/// memref<?x?xf32, stride_specification>,
+/// memref<?x?xf32, stride_specification>,
+/// memref<?x?xf32, stride_specification>
/// name mangles into `linalg_matmul_viewxxf32_viewxxf32_viewxxf32_impl`
std::string generateLibraryCallName(Operation *op);
let verifier = ?;
}
-def DimOp : Linalg_Op<"dim", [NoSideEffect]>,
- Arguments<(ins View:$view, APIntAttr:$index)>,
- Results<(outs Index)> {
- let summary = "dimension index operation";
- let description = [{
- The "linalg.dim" operation takes a linalg.view and returns an
- "index". It requires a single integer attribute named "index". It
- returns the size of the specified dimension.
-
- Example:
-
- %1 = linalg.dim %0, 2 : view<?x?x?xf32>
- }];
-
- let verifier = [{
- if (getIndex() >= getViewType().getRank())
- return emitOpError("index is out of range");
- return success();
- }];
-
- let builders = [OpBuilder<
- "Builder *builder, OperationState &result, Value *view, unsigned index",
- [{
- result.addOperands(view);
- result.addAttribute(
- "index", builder->getIntegerAttr(builder->getIndexType(), index));
- result.types.push_back(builder->getIndexType());
- }]>];
-
- let extraClassDeclaration = [{
- unsigned getIndex() {
- return getAttrOfType<IntegerAttr>("index").getValue().getZExtValue();
- }
- ViewType getViewType() { return getOperand()->getType().cast<ViewType>(); }
- }];
-
- let hasCanonicalizer = 1;
-}
-
-def LoadOp :
- Linalg_Op<"load"
- // TODO(ntv): activate once ViewType can be made a ShapeType (i.e.
- // shape type is extensible or standard adopts a reasonable view type).
- // , [ PredOpTrait<"operand and result have same element type",
- // TCresVTEtIsSameAsOpBase<0, 0>>]
- >,
- Arguments<(ins View:$view, Variadic<Index>:$indices)>,
- Results<(outs AnyType:$value)> {
- let summary = "Read an elemental value from a view at a certain index";
- let description = [{
- The `linalg.load` op reads an elemental value from a view at a certain
- index. This is the counterpart of other load ops but operating on ViewType.
-
- Example:
-
- %0 = linalg.load %V[%c0] : !linalg.view<?xf32>
- }];
- let builders = [OpBuilder<
- "Builder *builder, OperationState &result, Value *view, "
- "ArrayRef<Value*> indices",
- [{
- auto viewType = view->getType().cast<ViewType>();
- build(builder, result, viewType.getElementType(), view, indices);
- }]>];
- let extraClassDeclaration = [{
- unsigned getRank() { return getViewType().getRank(); }
- ViewType getViewType() { return view()->getType().cast<ViewType>(); }
- }];
-}
-
def RangeOp :
Linalg_Op<"range", [NoSideEffect]>,
Arguments<(ins Index:$min, Index:$max, Index:$step)>,
}
def SliceOp : Linalg_Op<"slice", [NoSideEffect]>,
- Arguments<(ins View:$view, Variadic<AnyTypeOf<[Range, Index]>>:$indexings)>,
- Results<(outs View)> {
+ Arguments<(ins AnyStridedMemRef:$view, Variadic<AnyTypeOf<[Range, Index]>>:$indexings)>,
+ Results<(outs AnyStridedMemRef)> {
let summary = "Produce a linalg.view which is a subview of a base view.";
let description = [{
The "linalg.slice" op produces a linalg.view which is a subview of a given
1. rank-preserving slice:
- %4 = linalg.slice %0[%1, %2] : !linalg.view<?x?xf32>, !linalg.range,
- !linalg.range, !linalg.view<?x?xf32>
+ %4 = linalg.slice %0[%1, %2] : memref<?x?xf32, stride_specification>,
+ !linalg.range, !linalg.range, memref<?x?xf32, stride_specification>
2. rank-reducing slice (from 2-D to 1-D):
- %4 = linalg.slice %0[%1, %2] : !linalg.view<?x?xf32>, index,
- !linalg.range, !linalg.view<?xf32>
+ %4 = linalg.slice %0[%1, %2] : memref<?x?xf32, stride_specification>,
+ index, !linalg.range, memref<?x?xf32, stride_specification>
3. rank-reducing slice (from 2-D to 0-D):
- %4 = linalg.slice %0[%1, %2] : !linalg.view<?x?xf32>, index, index,
- !linalg.view<f32>
+ %4 = linalg.slice %0[%1, %2] : memref<?x?xf32, stride_specification>,
+ index, index, memref<?x?xf32, stride_specification>
}];
let builders = [OpBuilder<
enum { FirstIndexingOperand = 1 };
unsigned getRank() { return getViewType().getRank(); }
Type getElementType() { return getViewType().getElementType(); }
- ViewType getViewType() { return getType().cast<ViewType>(); }
+ MemRefType getViewType() { return getType().cast<MemRefType>(); }
unsigned getBaseViewRank() { return getBaseViewType().getRank(); }
- ViewType getBaseViewType() { return view()->getType().cast<ViewType>(); }
+ MemRefType getBaseViewType() { return view()->getType().cast<MemRefType>(); }
// Get the underlying indexing at a given rank.
Value *indexing(unsigned rank) { return *(indexings().begin() + rank); }
}];
}
-def StoreOp :
- Linalg_Op<"store"
- // TODO(ntv): activate once ViewType can be made a ShapeType (i.e.
- // shape type is extensible or standard adopts a reasonable view type).
- // , [ PredOpTrait<"value to store and view have the same element type",
- // TCopVTEtIsSameAs<0, 1>>]
- >,
- Arguments<(ins AnyType:$value, View:$view, Variadic<Index>:$indices)>,
- Results<(outs)> {
- let summary = "Write an elemental value in a view at a certain index";
- let description = [{
- The `linalg.store` op writes an elemental value in a view at a certain
- index. This is the counterpart of other store ops but operating on ViewType.
-
- Example:
-
- linalg.store %f, %V[%c0] : !linalg.view<?xf32>
- }];
- let extraClassDeclaration = [{
- unsigned getRank() { return getViewType().getRank(); }
- ViewType getViewType() { return view()->getType().cast<ViewType>(); }
- }];
-}
-
def SubViewOp : Linalg_Op<"subview", [NoSideEffect]>,
- Arguments<(ins View:$view, Variadic<Index>:$ranges)>,
- Results<(outs View)> {
+ Arguments<(ins AnyStridedMemRef:$view, Variadic<Index>:$ranges)>,
+ Results<(outs AnyStridedMemRef)> {
let summary = "subview operation";
let description = [{
The "linalg.subview" op produces a linalg.view which is a subview of a given
Example:
- %1 = linalg.subview %0[%1, %2, %3, %4, %5, %6] : view<?x?xf32>
+ %1 = linalg.subview %0[%1, %2, %3, %4, %5, %6] :
+ memref<?x?xf32, stride_specification>
}];
// TODO(ntv) evolve syntax towards:
- // linalg.subview %0[%1:%2:%3][%4:%5:%6] : view<?x?xf32>
+ // linalg.subview %0[%1:%2:%3][%4:%5:%6] :
+ // memref<?x?xf32, stride_specification>
let builders = [OpBuilder<
- "Builder *builder, OperationState &result, Value *view, "
- "ArrayRef<Value *> ranges",
- [{
- result.addOperands(view);
- result.addOperands(ranges);
- result.types.push_back(view->getType());
- }]>];
+ "Builder *b, OperationState &result, Value *buffer, "
+ "ArrayRef<Value *> ranges, Type resultType = Type(), "
+ "ArrayRef<NamedAttribute> attrs = {}">];
let verifier = [{
auto rank = getViewType().getRank();
if (getNumOperands() != 3 * rank + 1)
- return emitOpError("expected a view followed by ") << (3 * rank) <<
- " indices specifying a range for each dimension";
+ return emitOpError("expected a strided memref followed by ") << (3 * rank)
+ << " indices specifying a range for each dimension";
return success();
}];
let extraClassDeclaration = [{
Value *getView() { return getOperand(0); }
- ViewType getViewType() { return getView()->getType().cast<ViewType>(); }
+ MemRefType getViewType() { return getView()->getType().cast<MemRefType>(); }
struct Range { Value *min; Value *max; Value *step; };
}
def TransposeOp : Linalg_Op<"transpose", [NoSideEffect]>,
- Arguments<(ins View:$view, AffineMapAttr:$permutation)>,
- Results<(outs View)> {
- let summary = "transpose operation produces a new view (metadata-only)";
+ Arguments<(ins AnyStridedMemRef:$view, AffineMapAttr:$permutation)>,
+ Results<(outs AnyStridedMemRef)> {
+ let summary = "transpose operation produces a new strided memref (metadata-only)";
let description = [{
- The "linalg.transpose" op produces a linalg.view whose sizes and strides are
- a permutation of the original. This is a pure metadata transformation.
+ The "linalg.transpose" op produces a strided memref whose sizes and strides
+ are a permutation of the original. This is a pure metadata transformation.
Example:
- %1 = linalg.transpose %0 (i, j) -> (j, i) : !linalg.view<?x?xf32>
+ %1 = linalg.transpose %0 (i, j) -> (j, i) :
+ memref<?x?xf32, stride_specification>
}];
let builders = [OpBuilder<
let extraClassDeclaration = [{
static StringRef getPermutationAttrName() { return "permutation"; }
- ViewType getViewType() { return view()->getType().cast<ViewType>(); }
+ MemRefType getViewType() { return view()->getType().cast<MemRefType>(); }
}];
}
def ViewOp : Linalg_Op<"view", [NoSideEffect]>,
Arguments<(ins Buffer:$buffer, Variadic<Range>:$ranges)>,
- Results<(outs View)> {
+ Results<(outs AnyStridedMemRef)> {
let summary = "view operation";
let description = [{
- The "linalg.view" op produces a linalg.view which is a multi-dimensional
+ The "linalg.view" op produces a strided memref which is a multi-dimensional
range abstraction on top of an underlying linalg.buffer. This gives an
indexing structure to an otherwise non-indexable linalg.buffer.
%1 = linalg.buffer_alloc %0 : !linalg.buffer<f32>
%2 = linalg.range %arg2:%arg3:%arg4 : !linalg.range
- %3 = linalg.view %1[%2, %2] : !linalg.view<?x?xvector<4xf32>>
+ %3 = linalg.view %1[%2, %2] :
+ memref<?x?xvector<4xf32>, stride_specification>
}];
let builders = [OpBuilder<
enum { FirstIndexingOperand = 1 };
unsigned getRank() { return getViewType().getRank(); }
Type getElementType() { return getViewType().getElementType(); }
- ViewType getViewType() { return getType().cast<ViewType>(); }
+ MemRefType getViewType() { return getType().cast<MemRefType>(); }
/// Get the underlying indexing at a given rank.
Value *getRange(unsigned rank) {
assert(rank < getRank() && "rank overflow");
#ifndef MLIR_DIALECT_LINALG_LINALGTRAITS_H_
#define MLIR_DIALECT_LINALG_LINALGTRAITS_H_
-#include "mlir/IR/OpDefinition.h"
#include "mlir/Dialect/Linalg/IR/LinalgTypes.h"
+#include "mlir/IR/OpDefinition.h"
+#include "mlir/IR/StandardTypes.h"
#include "mlir/Support/LLVM.h"
namespace mlir {
return llvm::None;
}
/// Return the `i`-th input view type.
- mlir::linalg::ViewType getInputViewType(unsigned i) {
- return getInput(i)->getType().template cast<mlir::linalg::ViewType>();
+ MemRefType getInputViewType(unsigned i) {
+ return getInput(i)->getType().template cast<MemRefType>();
}
/// Return the range over input views.
Operation::operand_range getInputs() {
return llvm::None;
}
/// Return the `i`-th output view type.
- mlir::linalg::ViewType getOutputViewType(unsigned i) {
- return getOutput(i)->getType().template cast<mlir::linalg::ViewType>();
+ MemRefType getOutputViewType(unsigned i) {
+ return getOutput(i)->getType().template cast<MemRefType>();
}
/// Return the range over output views.
Operation::operand_range getOutputs() {
/// Return the number of input and output views.
unsigned getNumInputsAndOutputs() { return nInputs() + nOutputs(); }
/// Return the `i`-th view type.
- mlir::linalg::ViewType getViewType(unsigned i) {
+ MemRefType getViewType(unsigned i) {
return (i < nInputs()) ? getInputViewType(i)
: getOutputViewType(i - nInputs());
}
auto nViews = cast<ConcreteType>(op).getNumInputsAndOutputs();
if (failed(OpTrait::impl::verifyAtLeastNOperands(op, nViews)))
return failure();
- for (unsigned i = 0, e = nViews; i < e; ++i) {
- if (!op->getOperand(i)->getType().dyn_cast<mlir::linalg::ViewType>())
- return op->emitOpError("operand ") << i << " must have view type ";
- }
return success();
}
};
};
};
-/// This class provides the API for ops that are known to have a specified
-/// list of view ranks. This is used as a trait like this:
-///
-/// class MatvecOp : public Op<MatvecOp, OpTrait::ViewRanks<2, 1, 1>::Impl> {
-///
-template <unsigned... Ranks> class ViewRanks {
-public:
- template <typename ConcreteType>
- class Impl
- : public OpTrait::TraitBase<ConcreteType, ViewRanks<Ranks...>::Impl> {
- public:
- static LogicalResult verifyTrait(Operation *op) {
- if (op->getNumOperands() != sizeof...(Ranks))
- return op->emitError("expected ") << sizeof...(Ranks) << " operands";
-
- unsigned ranks[]{Ranks...};
- for (unsigned i = 0, e = op->getNumOperands(); i < e; ++i) {
- auto viewType =
- op->getOperand(i)->getType().dyn_cast<mlir::linalg::ViewType>();
- if (!viewType)
- return op->emitOpError("operand ") << i << " must have view type ";
- if (ranks[i] != viewType.getRank())
- return op->emitOpError("operand ")
- << i << " must have rank " << ranks[i];
- }
- return success();
- }
- };
-};
-
} // namespace linalg
} // namespace OpTrait
} // namespace mlir
enum LinalgTypes {
Buffer = Type::FIRST_LINALG_TYPE,
Range,
- View,
- LAST_USED_LINALG_TYPE = View,
+ LAST_USED_LINALG_TYPE = Range,
};
class LinalgDialect : public Dialect {
static bool kindof(unsigned kind) { return kind == LinalgTypes::Range; }
};
-/// A ViewType represents a multi-dimensional range abstraction on top of an
-/// underlying storage type. It is parameterizable by the underlying element
-/// type and the rank of the view.
-/// A new value of ViewType is constructed from a buffer with a view op and
-/// passing it ranges:
-///
-/// ```{.mlir}
-/// %1 = linalg.buffer_alloc %0 : !linalg.buffer<f32>
-/// %2 = linalg.range %arg2:%arg3:%arg4 : !linalg.range
-/// %3 = linalg.view %1[%2, %2] : !linalg.view<?x?xf32>
-/// ```
-struct ViewTypeStorage;
-class ViewType : public Type::TypeBase<ViewType, Type, ViewTypeStorage> {
-public:
- // Used for generic hooks in TypeBase.
- using Base::Base;
- /// Construction hook.
- static ViewType get(MLIRContext *context, Type elementType, unsigned rank);
- // Used to implement llvm-style cast.
- static bool kindof(unsigned kind) { return kind == LinalgTypes::View; }
-
- // Type-specific functionality.
- /// Return the underlying elemental type.
- Type getElementType();
- /// Return the rank of the view.
- /// This is the number of indexings needed to reach an underlying element.
- unsigned getRank();
-};
-
} // namespace linalg
} // namespace mlir
class BufferAllocOp;
class BufferDeallocOp;
class CopyOp;
-class DimOp;
class FillOp;
-class LoadOp;
class RangeOp;
class SliceOp;
-class StoreOp;
class ViewOp;
namespace intrinsics {
using buffer_alloc = mlir::edsc::intrinsics::ValueBuilder<BufferAllocOp>;
using buffer_dealloc =
mlir::edsc::intrinsics::OperationBuilder<BufferDeallocOp>;
using copy = mlir::edsc::intrinsics::OperationBuilder<CopyOp>;
-using dim = mlir::edsc::intrinsics::ValueBuilder<linalg::DimOp>;
using fill = mlir::edsc::intrinsics::OperationBuilder<FillOp>;
-using linalg_load = mlir::edsc::intrinsics::ValueBuilder<linalg::LoadOp>;
-using linalg_store = mlir::edsc::intrinsics::OperationBuilder<linalg::StoreOp>;
using range = mlir::edsc::intrinsics::ValueBuilder<RangeOp>;
using slice = mlir::edsc::intrinsics::ValueBuilder<SliceOp>;
using view = mlir::edsc::intrinsics::ValueBuilder<ViewOp>;
SmallVector<Value *, 8> getViewSizes(ConcreteOp linalgOp) {
SmallVector<Value *, 8> res;
for (auto v : linalgOp.getInputsAndOutputs()) {
- ViewType t = v->getType().template cast<ViewType>();
+ MemRefType t = v->getType().template cast<MemRefType>();
for (unsigned i = 0; i < t.getRank(); ++i)
- res.push_back(intrinsics::dim(v, i));
+ res.push_back(edsc::intrinsics::dim(v, i));
}
return res;
}
def AnyStaticShapeMemRef : StaticShapeMemRefOf<[AnyType]>;
+// For a MemRefType, verify that it has strides.
+def HasStridesPred : CPred<[{ isStrided($_self.cast<MemRefType>()) }]>;
+
+class StridedMemRefOf<list<Type> allowedTypes>
+ : Type<And<[MemRefOf<allowedTypes>.predicate, HasStridesPred]>,
+ "strided " # MemRefOf<allowedTypes>.description>;
+
+def AnyStridedMemRef : StridedMemRefOf<[AnyType]>;
+
+class AnyStridedMemRefOfRank<int rank> :
+ Type<And<[AnyStridedMemRef.predicate,
+ MemRefRankOf<[AnyType], [rank]>.predicate]>,
+ AnyStridedMemRef.description # " of rank " # rank>;
+
// This represents a generic tuple without any constraints on element type.
def AnyTuple : Type<IsTupleTypePred, "tuple">;
/// layout map, returns llvm::None.
///
/// The convention is that the strides for dimensions d0, .. dn appear in
- /// order followed by the constant offset, to make indexing intuitive into the
- /// result.
+ /// order to make indexing intuitive into the result.
static constexpr int64_t kDynamicStrideOrOffset =
std::numeric_limits<int64_t>::min();
- LogicalResult getStridesAndOffset(SmallVectorImpl<int64_t> &strides) const;
+ LogicalResult getStridesAndOffset(SmallVectorImpl<int64_t> &strides,
+ int64_t &offset) const;
static bool kindof(unsigned kind) { return kind == StandardTypes::MemRef; }
static bool kindof(unsigned kind) { return kind == StandardTypes::None; }
};
+
+/// Given a list of strides (in which MemRefType::kDynamicStrideOrOffset
+/// represents a dynamic value), return the single result AffineMap which
+/// represents the linearized strided layout map. Dimensions correspond to the
+/// offset followed by the strides in order. Symbols are inserted for each
+/// dynamic dimension in order. A stride cannot take value `0`.
+///
+/// Examples:
+/// =========
+///
+/// 1. For offset: 0 strides: ?, ?, 1 return
+/// (i, j, k)[M, N]->(M * i + N * j + k)
+///
+/// 2. For offset: 3 strides: 32, ?, 16 return
+/// (i, j, k)[M]->(3 + 32 * i + M * j + 16 * k)
+///
+/// 3. For offset: ? strides: ?, ?, ? return
+/// (i, j, k)[off, M, N, P]->(off + M * i + N * j + P * k)
+AffineMap makeStridedLinearLayoutMap(ArrayRef<int64_t> strides, int64_t offset,
+ MLIRContext *context);
+
+bool isStrided(MemRefType t);
+
} // end namespace mlir
#endif // MLIR_IR_STANDARDTYPES_H
static unsigned kSizePosInMemRefDescriptor = 2;
static unsigned kStridePosInMemRefDescriptor = 3;
Type LLVMTypeConverter::convertMemRefType(MemRefType type) {
+ int64_t offset;
SmallVector<int64_t, 4> strides;
- bool strideSuccess = succeeded(type.getStridesAndOffset(strides));
+ bool strideSuccess = succeeded(type.getStridesAndOffset(strides, offset));
assert(strideSuccess &&
"Non-strided layout maps must have been normalized away");
(void)strideSuccess;
if (isSupportedMemRefType(type))
return matchSuccess();
- SmallVector<int64_t, 4> stridesAndOffset;
- auto successStrides = type.getStridesAndOffset(stridesAndOffset);
+ int64_t offset;
+ SmallVector<int64_t, 4> strides;
+ auto successStrides = type.getStridesAndOffset(strides, offset);
if (failed(successStrides))
return matchFailure();
// Dynamic strides are ok if they can be deduced from dynamic sizes (which
// is guaranteed when succeeded(successStrides)).
// Dynamic offset however can never be alloc'ed.
- if (stridesAndOffset.back() != MemRefType::kDynamicStrideOrOffset)
+ if (offset != MemRefType::kDynamicStrideOrOffset)
return matchFailure();
return matchSuccess();
allocated = rewriter.create<LLVM::BitcastOp>(op->getLoc(), elementPtrType,
ArrayRef<Value *>(allocated));
- SmallVector<int64_t, 4> stridesAndOffset;
- auto successStrides = type.getStridesAndOffset(stridesAndOffset);
+ int64_t offset;
+ SmallVector<int64_t, 4> strides;
+ auto successStrides = type.getStridesAndOffset(strides, offset);
assert(succeeded(successStrides) && "unexpected non-strided memref");
(void)successStrides;
+ assert(offset != MemRefType::kDynamicStrideOrOffset &&
+ "unexpected dynamic offset");
- ArrayRef<int64_t> strides = ArrayRef<int64_t>(stridesAndOffset).drop_back();
// 0-D memref corner case: they have size 1 ...
assert((type.getRank() == 0 && strides.empty() && sizes.size() == 1) ||
- (strides.size() == sizes.size()) && "unexpected number of stride");
+ (strides.size() == sizes.size()) && "unexpected number of strides");
// Create the MemRef descriptor.
auto structType = lowering.convertType(type);
rewriter.getIndexArrayAttr(kPtrPosInMemRefDescriptor));
memRefDescriptor = rewriter.create<LLVM::InsertValueOp>(
op->getLoc(), structType, memRefDescriptor,
- createIndexConstant(rewriter, op->getLoc(), stridesAndOffset.back()),
+ createIndexConstant(rewriter, op->getLoc(), offset),
rewriter.getIndexArrayAttr(kOffsetPosInMemRefDescriptor));
if (type.getRank() == 0)
- // No size/stride arrays in 0-D memref, use the descriptor value.
+ // No size/stride descriptor in memref, return the descriptor value.
return rewriter.replaceOp(op, memRefDescriptor);
- // Store all sizes in the descriptor.
+ // Store all sizes in the descriptor. Only dynamic sizes are passed in as
+ // operands to AllocOp.
Value *runningStride = nullptr;
// Iterate strides in reverse order, compute runningStride and strideValues.
auto nStrides = strides.size();
struct DimOpLowering : public LLVMLegalizationPattern<DimOp> {
using LLVMLegalizationPattern<DimOp>::LLVMLegalizationPattern;
- PatternMatchResult match(Operation *op) const override {
- auto dimOp = cast<DimOp>(op);
- MemRefType type = dimOp.getOperand()->getType().cast<MemRefType>();
- return isSupportedMemRefType(type) ? matchSuccess() : matchFailure();
- }
-
- void rewrite(Operation *op, ArrayRef<Value *> operands,
- ConversionPatternRewriter &rewriter) const override {
+ PatternMatchResult
+ matchAndRewrite(Operation *op, ArrayRef<Value *> operands,
+ ConversionPatternRewriter &rewriter) const override {
auto dimOp = cast<DimOp>(op);
OperandAdaptor<DimOp> transformed(operands);
MemRefType type = dimOp.getOperand()->getType().cast<MemRefType>();
auto shape = type.getShape();
int64_t index = dimOp.getIndex();
- // Extract dynamic size from the memref descriptor and define static size
- // as a constant.
+ // Extract dynamic size from the memref descriptor.
if (ShapedType::isDynamic(shape[index]))
rewriter.replaceOpWithNewOp<LLVM::ExtractValueOp>(
op, getIndexType(), transformed.memrefOrTensor(),
rewriter.getI64ArrayAttr({kSizePosInMemRefDescriptor, index}));
else
+ // Use constant for static size.
rewriter.replaceOp(
op, createIndexConstant(rewriter, op->getLoc(), shape[index]));
+ return matchSuccess();
}
};
Value *getStridedElementPtr(Location loc, Type elementTypePtr,
Value *memRefDescriptor,
ArrayRef<Value *> indices,
- ArrayRef<int64_t> stridesAndOffset,
+ ArrayRef<int64_t> strides, int64_t offset,
ConversionPatternRewriter &rewriter) const {
auto indexTy = this->getIndexType();
Value *base = rewriter.create<LLVM::ExtractValueOp>(
loc, elementTypePtr, memRefDescriptor,
rewriter.getIndexArrayAttr(kPtrPosInMemRefDescriptor));
- Value *offset =
- stridesAndOffset.back() == MemRefType::kDynamicStrideOrOffset
+ Value *offsetValue =
+ offset == MemRefType::kDynamicStrideOrOffset
? rewriter.create<LLVM::ExtractValueOp>(
loc, indexTy, memRefDescriptor,
rewriter.getIndexArrayAttr(kOffsetPosInMemRefDescriptor))
- : this->createIndexConstant(rewriter, loc, stridesAndOffset.back());
- auto strides = stridesAndOffset.drop_back();
+ : this->createIndexConstant(rewriter, loc, offset);
for (int i = 0, e = indices.size(); i < e; ++i) {
Value *stride;
if (strides[i] != MemRefType::kDynamicStrideOrOffset) {
}
Value *additionalOffset =
rewriter.create<LLVM::MulOp>(loc, indices[i], stride);
- offset = rewriter.create<LLVM::AddOp>(loc, offset, additionalOffset);
+ offsetValue =
+ rewriter.create<LLVM::AddOp>(loc, offsetValue, additionalOffset);
}
- return rewriter.create<LLVM::GEPOp>(loc, elementTypePtr, base, offset);
+ return rewriter.create<LLVM::GEPOp>(loc, elementTypePtr, base, offsetValue);
}
Value *getDataPtr(Location loc, MemRefType type, Value *memRefDesc,
ConversionPatternRewriter &rewriter,
llvm::Module &module) const {
auto ptrType = getMemRefElementPtrType(type, this->lowering);
- SmallVector<int64_t, 4> stridesAndOffset;
- auto res = type.getStridesAndOffset(stridesAndOffset);
- assert(succeeded(res) && "expected strided MemRef");
- (void)res;
- return getStridedElementPtr(loc, ptrType, memRefDesc, indices,
- stridesAndOffset, rewriter);
+ int64_t offset;
+ SmallVector<int64_t, 4> strides;
+ auto successStrides = type.getStridesAndOffset(strides, offset);
+ assert(succeeded(successStrides) && "unexpected non-strided memref");
+ (void)successStrides;
+ return getStridedElementPtr(loc, ptrType, memRefDesc, indices, strides,
+ offset, rewriter);
}
};
auto it = aliases.find(v);
if (it != aliases.end()) {
assert(((isa<BlockArgument>(it->getSecond()) &&
- it->getSecond()->getType().isa<ViewType>()) ||
+ it->getSecond()->getType().isa<MemRefType>()) ||
it->getSecond()->getType().isa<BufferType>()) &&
"Buffer or block argument expected");
return it->getSecond();
using namespace mlir::edsc::intrinsics;
using namespace mlir::linalg;
-namespace {
-/// Fold constant dimensions into an alloc operation.
-struct SimplifyDimOp : public OpRewritePattern<linalg::DimOp> {
- using OpRewritePattern<linalg::DimOp>::OpRewritePattern;
-
- PatternMatchResult matchAndRewrite(linalg::DimOp dimOp,
- PatternRewriter &rewriter) const override;
-};
-} // end namespace
-
-PatternMatchResult
-SimplifyDimOp::matchAndRewrite(linalg::DimOp dimOp,
- PatternRewriter &rewriter) const {
- auto *viewProducingOp = dimOp.view()->getDefiningOp();
- auto subView = dyn_cast_or_null<SubViewOp>(viewProducingOp);
- auto slice = dyn_cast_or_null<SliceOp>(viewProducingOp);
- auto view = dyn_cast_or_null<ViewOp>(viewProducingOp);
- assert(subView || slice || view);
-
- unsigned dim = dimOp.getIndex();
- Value *min, *max, *step;
- if (view) {
- // Cannot traverse block arguments, fail.
- if (isa<BlockArgument>(view.getRange(dim)))
- return matchFailure();
- // Record min, max, step for further processing.
- auto range = cast<RangeOp>(view.getRange(dim)->getDefiningOp());
- std::tie(min, max, step) =
- std::make_tuple(range.min(), range.max(), range.step());
- } else if (subView) {
- // Record min, max, step for further processing.
- auto range = subView.getRange(dim);
- std::tie(min, max, step) =
- std::make_tuple(range.min, range.max, range.step);
- } else {
- // Taking the dim of a slice must take a range (since other dims have been
- // rank-reduced).
- auto *rangeValue = slice.getRanges()[dim];
- // Cannot traverse block arguments, fail.
- if (isa<BlockArgument>(rangeValue))
- return matchFailure();
- auto range = cast<RangeOp>(rangeValue->getDefiningOp());
- // Record min, max, step for further processing.
- std::tie(min, max, step) =
- std::make_tuple(range.min(), range.max(), range.step());
- }
-
- // Only support constant steps of 1 atm.
- auto constant = dyn_cast_or_null<ConstantIndexOp>(step->getDefiningOp());
- if (!constant || constant.getValue() != 1)
- return matchFailure();
-
- // Circumvent affine constraints:
- // emit an affine_apply when possible, otherwise emit a `subi`.
- bool validAffineMin = isValidDim(min) || isValidSymbol(min) ||
- isa_and_nonnull<ConstantIndexOp>(min->getDefiningOp());
- bool validAffineMax = isValidDim(max) || isValidSymbol(max) ||
- isa_and_nonnull<ConstantIndexOp>(max->getDefiningOp());
-
- OpBuilder b(dimOp);
- ScopedContext scope(b, dimOp.getLoc());
- // Emit `subi`.
- if (!validAffineMin || !validAffineMax) {
- rewriter.replaceOp(dimOp, {subi(max, min)}, {dimOp.view()});
- return matchSuccess();
- }
-
- // Emit affine_apply.
- using edsc::op::operator-;
- rewriter.replaceOp(dimOp, {ValueHandle(max) - ValueHandle(min)},
- {dimOp.view()});
- return matchSuccess();
-}
-
///////////////////// Operations defined with Tablegen /////////////////////////
// For such operations that do not correspond to library calls (i.e. defined in
// LinalgOps.td), we define an overloaded `print` function and a
}
//===----------------------------------------------------------------------===//
-// DimOp
-//===----------------------------------------------------------------------===//
-void mlir::linalg::DimOp::getCanonicalizationPatterns(
- OwningRewritePatternList &results, MLIRContext *context) {
- results.insert<SimplifyDimOp>(context);
-}
-
-static void print(OpAsmPrinter &p, linalg::DimOp op) {
- p << op.getOperationName() << " " << *op.getOperand() << ", "
- << op.getIndex();
- p.printOptionalAttrDict(op.getAttrs(), /*elidedAttrs=*/{"index"});
- p << " : " << op.getOperand()->getType();
-}
-
-static ParseResult parseDimOp(OpAsmParser &parser, OperationState &result) {
- OpAsmParser::OperandType operandInfo;
- IntegerAttr indexAttr;
- Type type;
- Type indexType = parser.getBuilder().getIndexType();
- return failure(
- parser.parseOperand(operandInfo) || parser.parseComma() ||
- parser.parseAttribute(indexAttr, indexType, "index", result.attributes) ||
- parser.parseOptionalAttributeDict(result.attributes) ||
- parser.parseColonType(type) ||
- parser.resolveOperand(operandInfo, type, result.operands) ||
- parser.addTypeToList(indexType, result.types));
-}
-
-//===----------------------------------------------------------------------===//
// GenericOp
//===----------------------------------------------------------------------===//
}
//===----------------------------------------------------------------------===//
-// LoadOp
-//===----------------------------------------------------------------------===//
-
-static void print(OpAsmPrinter &p, linalg::LoadOp op) {
- p << op.getOperationName() << " " << *op.view() << '[';
- p.printOperands(op.indices());
- p << ']';
- p.printOptionalAttrDict(op.getAttrs());
- p << " : " << op.getViewType();
-}
-
-static ParseResult parseLoadOp(OpAsmParser &parser, OperationState &result) {
- OpAsmParser::OperandType viewInfo;
- SmallVector<OpAsmParser::OperandType, 4> indexInfo;
- ViewType type;
-
- auto indexTy = parser.getBuilder().getIndexType();
- return failure(
- parser.parseOperand(viewInfo) ||
- parser.parseOperandList(indexInfo, OpAsmParser::Delimiter::Square) ||
- parser.parseOptionalAttributeDict(result.attributes) ||
- parser.parseColonType(type) ||
- parser.resolveOperand(viewInfo, type, result.operands) ||
- parser.resolveOperands(indexInfo, indexTy, result.operands) ||
- parser.addTypeToList(type.getElementType(), result.types));
-}
-
-static LogicalResult verify(linalg::LoadOp op) {
- if (op.getRank() != llvm::size(op.indices()))
- return op.emitOpError("expected ")
- << op.getRank() << " indices, got " << llvm::size(op.indices());
- return success();
-}
-
-//===----------------------------------------------------------------------===//
// RangeOp
//===----------------------------------------------------------------------===//
result.addOperands(base);
result.addOperands(indexings);
- ViewType viewType = base->getType().cast<ViewType>();
- unsigned rank = viewType.getRank();
- for (auto *i : indexings)
- if (!i->getType().isa<RangeType>())
- rank--;
- Type elementType = viewType.getElementType();
- result.addTypes({ViewType::get(b->getContext(), elementType, rank)});
+ auto memRefType = base->getType().cast<MemRefType>();
+ int64_t offset;
+ SmallVector<int64_t, 4> strides;
+ auto res = memRefType.getStridesAndOffset(strides, offset);
+ assert(succeeded(res) && strides.size() == indexings.size());
+ (void)res;
+
+ unsigned rank = memRefType.getRank();
+ // TODO(ntv): propagate static size and stride information when available.
+ SmallVector<int64_t, 4> sizes(rank, -1); // -1 encodes dynamic size.
+ Type elementType = memRefType.getElementType();
+ result.addTypes({MemRefType::get(
+ sizes, elementType,
+ {makeStridedLinearLayoutMap(strides, offset, b->getContext())},
+ memRefType.getMemorySpace())});
}
static void print(OpAsmPrinter &p, SliceOp op) {
}
//===----------------------------------------------------------------------===//
-// StoreOp
-//===----------------------------------------------------------------------===//
-
-static void print(OpAsmPrinter &p, linalg::StoreOp op) {
- p << op.getOperationName() << " " << *op.value();
- p << ", " << *op.view() << '[';
- p.printOperands(op.indices());
- p << ']';
- p.printOptionalAttrDict(op.getAttrs());
- p << " : " << op.getViewType();
-}
-
-static ParseResult parseStoreOp(OpAsmParser &parser, OperationState &result) {
- OpAsmParser::OperandType storeValueInfo;
- OpAsmParser::OperandType viewInfo;
- SmallVector<OpAsmParser::OperandType, 4> indexInfo;
- ViewType viewType;
-
- auto indexTy = parser.getBuilder().getIndexType();
- return failure(
- parser.parseOperand(storeValueInfo) || parser.parseComma() ||
- parser.parseOperand(viewInfo) ||
- parser.parseOperandList(indexInfo, OpAsmParser::Delimiter::Square) ||
- parser.parseOptionalAttributeDict(result.attributes) ||
- parser.parseColonType(viewType) ||
- parser.resolveOperand(storeValueInfo, viewType.getElementType(),
- result.operands) ||
- parser.resolveOperand(viewInfo, viewType, result.operands) ||
- parser.resolveOperands(indexInfo, indexTy, result.operands));
-}
-
-static LogicalResult verify(linalg::StoreOp op) {
- if (op.value()->getType() != op.getViewType().getElementType())
- return op.emitOpError("expected value type to match view element type");
- if (op.getRank() != llvm::size(op.indices()))
- return op.emitOpError("expected ")
- << op.getRank() << " indices, got " << llvm::size(op.indices());
- return success();
-}
-
-//===----------------------------------------------------------------------===//
// SubViewOp
//===----------------------------------------------------------------------===//
+void mlir::linalg::SubViewOp::build(Builder *b, OperationState &result,
+ Value *view, ArrayRef<Value *> ranges,
+ Type resultType,
+ ArrayRef<NamedAttribute> attrs) {
+ // If the result type is not specified, assume sizes are fully dynamic.
+ // Strides don't change though.
+ // TODO(ntv) for canonicalization it may be better to use a (min, size, step)
+ // instead of a (min, max, step) abstraction.
+ if (!resultType) {
+ auto rank = ranges.size();
+ SmallVector<int64_t, 4> sizes(rank, -1);
+ auto memRefType = view->getType().cast<MemRefType>();
+ Type elementType = memRefType.getElementType();
+ resultType = MemRefType::get(sizes, elementType, memRefType.getAffineMaps(),
+ memRefType.getMemorySpace());
+ }
+ build(b, result, resultType, view, ranges);
+ result.addAttributes(attrs);
+}
static void print(OpAsmPrinter &p, SubViewOp op) {
p << op.getOperationName() << " " << *op.getOperand(0) << "[";
static ParseResult parseSubViewOp(OpAsmParser &parser, OperationState &result) {
OpAsmParser::OperandType inputView, resultView;
- Type viewType;
+ MemRefType memRefType;
if (parser.parseOperand(inputView))
return failure();
// linalg.subview %0[%1:%2:%3][%4:%5:%6]
if (parser.parseOperandList(ops, OpAsmParser::Delimiter::Square) ||
parser.parseOptionalAttributeDict(result.attributes) ||
- parser.parseColonType(viewType))
+ parser.parseColonType(memRefType))
return failure();
auto indexTy = parser.getBuilder().getIndexType();
- return failure(parser.resolveOperand(inputView, viewType, result.operands) ||
- parser.resolveOperands(ops, indexTy, result.operands) ||
- parser.addTypeToList(viewType, result.types));
+ return failure(
+ parser.resolveOperand(inputView, memRefType, result.operands) ||
+ parser.resolveOperands(ops, indexTy, result.operands) ||
+ parser.addTypeToList(memRefType, result.types));
}
//===----------------------------------------------------------------------===//
void mlir::linalg::TransposeOp::build(Builder *b, OperationState &result,
Value *view, AffineMapAttr permutation,
ArrayRef<NamedAttribute> attrs) {
- // TODO(ntv): once views have static dimensions, compute the permuted type.
- build(b, result, view->getType(), view, attrs);
+ auto permutationMap = permutation.getValue();
+ assert(permutationMap);
+
+ auto memRefType = view->getType().cast<MemRefType>();
+ auto rank = memRefType.getRank();
+ auto originalSizes = memRefType.getShape();
+ // Compute permuted sizes.
+ SmallVector<int64_t, 4> sizes(rank, 0);
+ for (auto en : llvm::enumerate(permutationMap.getResults()))
+ sizes[en.index()] =
+ originalSizes[en.value().cast<AffineDimExpr>().getPosition()];
+
+ // Compute permuted strides.
+ int64_t offset;
+ SmallVector<int64_t, 4> strides;
+ auto res = memRefType.getStridesAndOffset(strides, offset);
+ assert(succeeded(res) && strides.size() == static_cast<unsigned>(rank));
+ (void)res;
+ auto map = makeStridedLinearLayoutMap(strides, offset, b->getContext());
+ map = permutationMap ? map.compose(permutationMap) : map;
+ // Compute result type.
+ auto resultType = MemRefType::get(sizes, memRefType.getElementType(), map,
+ memRefType.getMemorySpace());
+
+ build(b, result, resultType, view, attrs);
result.addAttribute(TransposeOp::getPermutationAttrName(), permutation);
}
OperationState &result) {
OpAsmParser::OperandType view;
AffineMapAttr permutation;
- Type type;
+ MemRefType type;
return failure(parser.parseOperand(view) ||
parser.parseAttribute(permutation,
TransposeOp::getPermutationAttrName(),
Value *buffer, ArrayRef<Value *> ranges,
Type resultType,
ArrayRef<NamedAttribute> attrs) {
+ // If the result type is not specified, assume sizes are fully dynamic.
+ // Strides are set to match an empty layout map which means "contiguous view".
if (!resultType) {
+ auto rank = ranges.size();
+ SmallVector<int64_t, 4> sizes(rank, -1);
Type elementType = buffer->getType().cast<BufferType>().getElementType();
- resultType = ViewType::get(b->getContext(), elementType, ranges.size());
+ resultType = MemRefType::get(sizes, elementType, {}, 0);
}
build(b, result, resultType, buffer, ranges);
result.addAttributes(attrs);
return failure();
}
- ViewType viewType = vType.dyn_cast<ViewType>();
- if (!viewType)
- return parser.emitError(parser.getNameLoc(), "expected view type");
- if (viewType.getRank() != rangesInfo.size())
+ MemRefType memRefType = vType.dyn_cast<MemRefType>();
+ if (!memRefType)
+ return parser.emitError(parser.getNameLoc(), "expected memref type");
+ if (static_cast<unsigned>(memRefType.getRank()) != rangesInfo.size())
return parser.emitError(parser.getNameLoc(), "expected ")
- << viewType.getRank() << " ranges";
+ << memRefType.getRank() << " ranges";
return failure(
parser.resolveOperand(bufferInfo, bType, result.operands) ||
(!rangesInfo.empty() &&
parser.resolveOperands(rangesInfo, RangeType::get(vType.getContext()),
result.operands)) ||
- parser.addTypeToList(viewType, result.types));
+ parser.addTypeToList(memRefType, result.types));
}
//===----------------------------------------------------------------------===//
//
// ```
// linalg.matmul(%0, %1, %2) :
-// !linalg.view<?x?xf32>, !linalg.view<?x?xf32>, !linalg.view<?x?xf32>
+// memref<?x?xf32, stride_specification>,
+// memref<?x?xf32, stride_specification>,
+// memref<?x?xf32, stride_specification>
// ```
//
-// Where %0, %1 and %2 are ssa-values of type ViewType.
+// Where %0, %1 and %2 are ssa-values of type MemRefType with strides.
static void printLinalgLibraryOp(OpAsmPrinter &p, Operation *op) {
assert(op->getAbstractOperation() && "unregistered operation");
p << op->getName().getStringRef() << "(";
}
static LogicalResult verify(ConvOp op) {
- auto oType = op.output()->getType().cast<ViewType>();
- auto fType = op.filter()->getType().cast<ViewType>();
- auto iType = op.input()->getType().cast<ViewType>();
+ auto oType = op.output()->getType().cast<MemRefType>();
+ auto fType = op.filter()->getType().cast<MemRefType>();
+ auto iType = op.input()->getType().cast<MemRefType>();
if (oType.getElementType() != iType.getElementType() ||
oType.getElementType() != fType.getElementType())
- return op.emitOpError("expects view elemental types to match");
+ return op.emitOpError("expects memref elemental types to match");
if (oType.getRank() != iType.getRank() || oType.getRank() != fType.getRank())
- return op.emitOpError("expects view ranks to match");
+ return op.emitOpError("expects memref ranks to match");
if (auto strides = op.strides()) {
if (failed(
verifyStrideOrDilation(op, strides->getValue(), /*isStride=*/true)))
}
static void appendMangledType(llvm::raw_string_ostream &ss, Type t) {
- if (auto view = t.dyn_cast<ViewType>()) {
+ if (auto memref = t.dyn_cast<MemRefType>()) {
ss << "view";
- for (unsigned i = 0, e = view.getRank(); i < e; ++i)
- ss << "x";
- appendMangledType(ss, view.getElementType());
+ for (auto size : memref.getShape())
+ if (size < 0)
+ ss << "sx";
+ else
+ ss << size << "x";
+ appendMangledType(ss, memref.getElementType());
} else if (auto vec = t.dyn_cast<VectorType>()) {
ss << "vector";
interleave(
mlir::linalg::LinalgDialect::LinalgDialect(MLIRContext *context)
: Dialect(getDialectNamespace(), context) {
- addTypes<BufferType, RangeType, ViewType>();
+ addTypes<BufferType, RangeType>();
addOperations<
#define GET_OP_LIST
#include "mlir/Dialect/Linalg/IR/LinalgOps.cpp.inc"
return (bufferSize == -1 ? BufferType::get(getContext(), t)
: BufferType::get(getContext(), t, bufferSize));
}
- } else if (spec.consume_front("view")) {
- if (spec.consume_front("<") && spec.consume_back(">")) {
- // Just count the number of ? to get the rank.
- unsigned rank = 0;
- for (unsigned i = 0, e = spec.size(); i < e; ++i) {
- if (spec.consume_front("?")) {
- ++rank;
- if (!spec.consume_front("x")) {
- emitError(loc, "expected a list of '?x' dimension specifiers: ")
- << spec;
- return Type();
- }
- }
- }
- if (auto t = mlir::parseType(spec, context))
- return ViewType::get(context, t, rank);
- }
}
return (emitError(loc, "unknown Linalg type: " + origSpec), Type());
}
-struct mlir::linalg::ViewTypeStorage : public TypeStorage {
- /// Underlying Key type to transport the payload needed to construct a custom
- /// type in a generic way.
- struct Key {
- Key(Type elementType, unsigned rank)
- : elementType(elementType), rank(rank) {}
- Type elementType;
- unsigned rank;
- };
- /// `KeyTy` is a necessary typename hook for MLIR's custom type unique'ing.
- using KeyTy = Key;
-
- /// Construction in the llvm::BumpPtrAllocator given a key.
- static ViewTypeStorage *construct(TypeStorageAllocator &allocator,
- const Key &key) {
- return new (allocator.allocate<ViewTypeStorage>()) ViewTypeStorage(key);
- }
-
- /// Equality operator for hashing.
- bool operator==(const Key &key) const {
- return elementType == key.elementType && rank == key.rank;
- }
-
- /// Hashing for unique'ing.
- static unsigned hashKey(const Key &key) {
- return llvm::hash_combine(key.elementType, key.rank);
- }
-
- unsigned getRank() { return rank; };
- Type getElementType() { return elementType; };
-
-private:
- ViewTypeStorage(const Key &key)
- : elementType(key.elementType), rank(key.rank) {}
-
- Type elementType;
- unsigned rank;
-};
-
-ViewType mlir::linalg::ViewType::get(MLIRContext *context, Type elementType,
- unsigned rank) {
- return Base::get(context, LinalgTypes::View, elementType, rank);
-}
-
-Type mlir::linalg::ViewType::getElementType() {
- return getImpl()->getElementType();
-}
-
-unsigned mlir::linalg::ViewType::getRank() { return getImpl()->getRank(); }
/// BufferType prints as "buffer<element_type>".
static void print(BufferType bt, raw_ostream &os) {
/// RangeType prints as just "range".
static void print(RangeType rt, raw_ostream &os) { os << "range"; }
-/// ViewType prints as:
-///
-/// ```{.mlir}
-/// view<?x?xf32>
-/// ```
-///
-/// or
-///
-/// ```{.mlir}
-/// view<?xf32>
-/// ```
-///
-/// for 0-D views (a.k.a pointer to a scalar value).
-static void print(mlir::linalg::ViewType rt, raw_ostream &os) {
- os << "view<";
- for (unsigned i = 0, e = rt.getRank(); i < e; ++i) {
- os << "?x";
- }
- os << rt.getElementType();
- os << ">";
-}
-
void mlir::linalg::LinalgDialect::printType(Type type, raw_ostream &os) const {
switch (type.getKind()) {
default:
case LinalgTypes::Range:
print(type.cast<RangeType>(), os);
break;
- case LinalgTypes::View:
- print(type.cast<ViewType>(), os);
- break;
}
}
<< "existing LoopRange: " << loopRanges[i] << "\n");
else {
auto viewDim = getViewDefiningLoopRange(producer, i);
- loopRanges[i] = SubViewOp::Range{
- state.create<ConstantIndexOp>(b, loc, 0),
- linalg::intrinsics::dim(viewDim.view, viewDim.dimension),
- state.create<ConstantIndexOp>(b, loc, 1)};
+ loopRanges[i] =
+ SubViewOp::Range{state.create<ConstantIndexOp>(b, loc, 0),
+ dim(viewDim.view, viewDim.dimension),
+ state.create<ConstantIndexOp>(b, loc, 1)};
LLVM_DEBUG(llvm::dbgs() << "new LoopRange: " << loopRanges[i] << "\n");
}
}
if (t.isa<RangeType>())
return LLVMType::getStructTy(int64Ty, int64Ty, int64Ty);
- // A linalg.view type converts to a view descriptor. The view descriptor
- // contains the pointer to the data buffer, followed by a 64-bit integer
- // containing the distance between the beginning of the buffer and the first
- // element to be accessed through the view, followed by two arrays, each
- // containing as many 64-bit integers as the rank of the View. The first array
- // represents the size, in number of original elements, of the view along the
- // given dimension. When taking the view, the size is the difference between
- // the upper and the lower bound of the range. The second array represents the
- // "stride" (in tensor abstraction sense), i.e. the number of consecutive
- // elements of the underlying buffer that separate two consecutive elements
- // addressable through the view along the given dimension. When taking the
- // view, the strides are constructed as products of the original sizes along
- // the trailing dimensions, multiplied by the view step. For example, a view
- // of a MxN memref with ranges {0:M:1}, {0:N:1}, i.e. the view of a complete
- // memref, will have strides N and 1. A view with ranges {0:M:2}, {0:N:3}
- // will have strides 2*N and 3.
- //
- // template <typename Elem, size_t Rank>
- // struct {
- // Elem *ptr;
- // int64_t offset;
- // int64_t sizes[Rank];
- // int64_t strides[Rank];
- // };
- if (auto viewType = t.dyn_cast<ViewType>()) {
- auto ptrTy = getPtrToElementType(viewType, lowering);
- auto arrayTy = LLVMType::getArrayTy(int64Ty, viewType.getRank());
- return LLVMType::getStructTy(ptrTy, int64Ty, arrayTy, arrayTy);
- }
-
return Type();
}
/// 3. view descriptor construction `desc`.
class BaseViewConversionHelper {
public:
- BaseViewConversionHelper(Operation *op, ViewType viewType,
+ BaseViewConversionHelper(Location loc, MemRefType memRefType,
ConversionPatternRewriter &rewriter,
LLVMTypeConverter &lowering)
- : elementTy(getPtrToElementType(viewType, lowering)),
+ : zeroDMemRef(memRefType.getRank() == 0),
+ elementTy(getPtrToElementType(memRefType, lowering)),
int64Ty(
lowering.convertType(rewriter.getIntegerType(64)).cast<LLVMType>()),
- rewriter(rewriter) {
- viewDescriptorTy = convertLinalgType(viewType, lowering).cast<LLVMType>();
- desc = rewriter.create<LLVM::UndefOp>(op->getLoc(), viewDescriptorTy);
+ desc(nullptr), rewriter(rewriter) {
+ assert(isStrided(memRefType) && "expected strided memref type");
+ viewDescriptorTy = lowering.convertType(memRefType).cast<LLVMType>();
+ desc = rewriter.create<LLVM::UndefOp>(loc, viewDescriptorTy);
}
ArrayAttr pos(ArrayRef<int64_t> values) const {
return rewriter.getI64ArrayAttr(values);
};
+ bool zeroDMemRef;
LLVMType elementTy, int64Ty, viewDescriptorTy;
- ConversionPatternRewriter &rewriter;
Value *desc;
+ ConversionPatternRewriter &rewriter;
};
} // namespace
}
};
-// DimOp creates a new `index` value.
-class DimOpConversion : public LLVMOpLowering {
-public:
- explicit DimOpConversion(MLIRContext *context, LLVMTypeConverter &lowering_)
- : LLVMOpLowering(linalg::DimOp::getOperationName(), context, lowering_) {}
-
- PatternMatchResult
- matchAndRewrite(Operation *op, ArrayRef<Value *> operands,
- ConversionPatternRewriter &rewriter) const override {
- auto dimOp = cast<linalg::DimOp>(op);
- auto indexTy = lowering.convertType(rewriter.getIndexType());
- edsc::ScopedContext context(rewriter, op->getLoc());
- auto pos = rewriter.getI64ArrayAttr(
- {kSizePosInView, static_cast<int>(dimOp.getIndex())});
- linalg::DimOpOperandAdaptor adaptor(operands);
- Value *viewDescriptor = adaptor.view();
- rewriter.replaceOp(op, {extractvalue(indexTy, viewDescriptor, pos)});
- return matchSuccess();
- }
-};
-
-namespace {
-// Common functionality for Linalg LoadOp and StoreOp conversion to the
-// LLVM IR Dialect.
-template <typename Op> class LoadStoreOpConversion : public LLVMOpLowering {
-public:
- explicit LoadStoreOpConversion(MLIRContext *context,
- LLVMTypeConverter &lowering_)
- : LLVMOpLowering(Op::getOperationName(), context, lowering_) {}
- using Base = LoadStoreOpConversion<Op>;
-
- // Compute the pointer to an element of the buffer underlying the view given
- // current view indices. Use the base offset and strides stored in the view
- // descriptor to emit IR iteratively computing the actual offset, followed by
- // a getelementptr. This must be called under an edsc::ScopedContext.
- Value *obtainDataPtr(Operation *op, Value *viewDescriptor,
- ArrayRef<Value *> indices,
- ConversionPatternRewriter &rewriter) const {
- auto loadOp = cast<Op>(op);
- auto elementTy = getPtrToElementType(loadOp.getViewType(), lowering);
- auto int64Ty = lowering.convertType(rewriter.getIntegerType(64));
- auto pos = [&rewriter](ArrayRef<int64_t> values) {
- return rewriter.getI64ArrayAttr(values);
- };
-
- // Linearize subscripts as:
- // base_offset + SUM_i index_i * stride_i.
- Value *base = extractvalue(elementTy, viewDescriptor, pos(kPtrPosInView));
- Value *offset =
- extractvalue(int64Ty, viewDescriptor, pos(kOffsetPosInView));
- for (int i = 0, e = loadOp.getRank(); i < e; ++i) {
- Value *stride =
- extractvalue(int64Ty, viewDescriptor, pos({kStridePosInView, i}));
- Value *additionalOffset = mul(indices[i], stride);
- offset = add(offset, additionalOffset);
- }
- return gep(elementTy, base, offset);
- }
-};
-} // namespace
-
-// A load is converted into the actual address computation, getelementptr and
-// an LLVM IR load.
-class LoadOpConversion : public LoadStoreOpConversion<linalg::LoadOp> {
- using Base::Base;
- PatternMatchResult
- matchAndRewrite(Operation *op, ArrayRef<Value *> operands,
- ConversionPatternRewriter &rewriter) const override {
- edsc::ScopedContext edscContext(rewriter, op->getLoc());
- auto elementTy = lowering.convertType(*op->result_type_begin());
- linalg::LoadOpOperandAdaptor adaptor(operands);
- auto ptr = obtainDataPtr(op, adaptor.view(), adaptor.indices(), rewriter);
- rewriter.replaceOp(op, {llvm_load(elementTy, ptr)});
- return matchSuccess();
- }
-};
-
// RangeOp creates a new range descriptor.
class RangeOpConversion : public LLVMOpLowering {
public:
Value *baseDesc = adaptor.view();
auto sliceOp = cast<SliceOp>(op);
- BaseViewConversionHelper helper(op, sliceOp.getViewType(), rewriter,
- lowering);
+ auto memRefType = sliceOp.getBaseViewType();
+
+ BaseViewConversionHelper helper(op->getLoc(), sliceOp.getViewType(),
+ rewriter, lowering);
LLVMType elementTy = helper.elementTy, int64Ty = helper.int64Ty;
Value *desc = helper.desc;
- auto viewType = sliceOp.getBaseViewType();
-
edsc::ScopedContext context(rewriter, op->getLoc());
- Value *zero =
- constant(int64Ty, rewriter.getIntegerAttr(rewriter.getIndexType(), 0));
-
- auto ptrPos = helper.pos(kPtrPosInView);
- desc = insertvalue(desc, extractvalue(elementTy, baseDesc, ptrPos), ptrPos);
// TODO(ntv): extract sizes and emit asserts.
- SmallVector<Value *, 4> strides(viewType.getRank());
- for (int i = 0, e = viewType.getRank(); i < e; ++i) {
+ SmallVector<Value *, 4> strides(memRefType.getRank());
+ for (int i = 0, e = memRefType.getRank(); i < e; ++i)
strides[i] =
extractvalue(int64Ty, baseDesc, helper.pos({kStridePosInView, i}));
- }
- // Compute and insert base offset.
+ // Compute base offset.
Value *baseOffset =
extractvalue(int64Ty, baseDesc, helper.pos(kOffsetPosInView));
- for (int i = 0, e = viewType.getRank(); i < e; ++i) {
+ for (int i = 0, e = memRefType.getRank(); i < e; ++i) {
Value *indexing = adaptor.indexings()[i];
Value *min = indexing;
if (sliceOp.indexing(i)->getType().isa<RangeType>())
min = extractvalue(int64Ty, indexing, helper.pos(0));
baseOffset = add(baseOffset, mul(min, strides[i]));
}
+
+ // Insert base pointer.
+ auto ptrPos = helper.pos(kPtrPosInView);
+ desc = insertvalue(desc, extractvalue(elementTy, baseDesc, ptrPos), ptrPos);
+
+ // Insert base offset.
desc = insertvalue(desc, baseOffset, helper.pos(kOffsetPosInView));
+ // Corner case, no sizes or strides: early return the descriptor.
+ if (helper.zeroDMemRef)
+ return rewriter.replaceOp(op, desc), matchSuccess();
+
+ Value *zero =
+ constant(int64Ty, rewriter.getIntegerAttr(rewriter.getIndexType(), 0));
// Compute and insert view sizes (max - min along the range) and strides.
// Skip the non-range operands as they will be projected away from the view.
int numNewDims = 0;
}
};
-// A store is converted into the actual address computation, getelementptr and
-// an LLVM IR store.
-class StoreOpConversion : public LoadStoreOpConversion<linalg::StoreOp> {
- using Base::Base;
- PatternMatchResult
- matchAndRewrite(Operation *op, ArrayRef<Value *> operands,
- ConversionPatternRewriter &rewriter) const override {
- edsc::ScopedContext edscContext(rewriter, op->getLoc());
- linalg::StoreOpOperandAdaptor adaptor(operands);
- Value *ptr = obtainDataPtr(op, adaptor.view(), adaptor.indices(), rewriter);
- llvm_store(adaptor.value(), ptr);
- rewriter.replaceOp(op, llvm::None);
- return matchSuccess();
- }
-};
-
/// Conversion pattern that transforms a linalg.transpose op into:
/// 1. A function entry `alloca` operation to allocate a ViewDescriptor.
/// 2. A load of the ViewDescriptor from the pointer allocated in 1.
if (tranposeOp.permutation().isIdentity())
return rewriter.replaceOp(op, baseDesc), matchSuccess();
- BaseViewConversionHelper helper(op, tranposeOp.getViewType(), rewriter,
- lowering);
+ BaseViewConversionHelper helper(op->getLoc(), tranposeOp.getViewType(),
+ rewriter, lowering);
LLVMType elementTy = helper.elementTy, int64Ty = helper.int64Ty;
Value *desc = helper.desc;
ViewOpOperandAdaptor adaptor(operands);
auto viewOp = cast<ViewOp>(op);
- BaseViewConversionHelper helper(op, viewOp.getViewType(), rewriter,
- lowering);
+ BaseViewConversionHelper helper(op->getLoc(), viewOp.getViewType(),
+ rewriter, lowering);
LLVMType elementTy = helper.elementTy, int64Ty = helper.int64Ty;
Value *desc = helper.desc;
Value *baseOffset = constant(int64Ty, IntegerAttr::get(indexTy, 0));
desc = insertvalue(desc, baseOffset, helper.pos(kOffsetPosInView));
+ // Corner case, no sizes or stride: early return the descriptor.
+ if (helper.zeroDMemRef) {
+ rewriter.replaceOp(op, desc);
+ return matchSuccess();
+ }
+
// Compute and insert view sizes (max - min along the range).
int numRanges = llvm::size(viewOp.ranges());
Value *runningStride = constant(int64Ty, IntegerAttr::get(indexTy, 1));
}
};
-// Promote LLVM struct types to pointer to struct types to avoid ABI issues
-// related to C struct packing.
-static SmallVector<Type, 4>
-promoteStructTypes(Operation::operand_range operands,
- LLVMTypeConverter &lowering) {
- SmallVector<Type, 4> res;
- for (auto operand : operands) {
- auto type = lowering.convertType(operand->getType()).cast<LLVM::LLVMType>();
- if (type.isStructTy())
- res.push_back(type.getPointerTo());
- else
- res.push_back(type);
- }
- return res;
-}
-
-// Promote LLVM struct to pointer to struct to avoid ABI issues related to
-// C struct packing.
-static SmallVector<Value *, 4>
-promoteStructs(Location loc, ArrayRef<Value *> operands,
- ConversionPatternRewriter &rewriter,
- LLVMTypeConverter &lowering) {
- auto *context = rewriter.getContext();
- auto int64Ty = LLVM::LLVMType::getInt64Ty(lowering.getDialect());
- auto indexType = IndexType::get(context);
- edsc::ScopedContext scope(rewriter, loc);
- SmallVector<Value *, 4> promotedOperands;
- promotedOperands.reserve(operands.size());
- for (auto *operand : operands) {
- auto type = operand->getType().cast<LLVM::LLVMType>();
- if (!type.isStructTy()) {
- promotedOperands.push_back(operand);
- continue;
- }
- // Alloca with proper alignment. This is purely for solving ABI issues
- // related to C struct packing across external library call boundaries. We
- // do not expect optimizations of this alloca op and so we omit
- // allocating at the entry block.
- auto ptrType = type.cast<LLVM::LLVMType>().getPointerTo();
- Value *one = constant(int64Ty, IntegerAttr::get(indexType, 1));
- Value *allocated = llvm_alloca(ptrType, one, /*alignment=*/8);
- // Store into the alloca'ed descriptor.
- llvm_store(operand, allocated);
- promotedOperands.push_back(allocated);
- }
- return promotedOperands;
-}
-
// Get function definition for the LinalgOp. If it doesn't exist, insert a
// definition.
template <typename LinalgOp>
-static FuncOp
-getLLVMLibraryCallDeclaration(Operation *op, LLVMTypeConverter &lowering,
- ConversionPatternRewriter &rewriter) {
+static FuncOp getLLVMLibraryCallDeclaration(Operation *op,
+ PatternRewriter &rewriter) {
auto linalgOp = cast<LinalgOp>(op);
auto fnName = linalgOp.getLibraryCallName();
if (fnName.empty()) {
return f;
}
- // Get the Function type consistent with LLVM Lowering.
- // Structs are automatically promoted to pointer to struct in order to avoid
- // ABI issues related to C struct packing that we don't want to handle here.
- auto inputTypes = promoteStructTypes(op->getOperands(), lowering);
+ SmallVector<Type, 4> inputTypes(op->getOperandTypes());
assert(op->getNumResults() == 0 &&
"Library call for linalg operation can be generated only for ops that "
"have void return types");
- auto libFnType = FunctionType::get(inputTypes, {}, op->getContext());
- auto libFn = FuncOp::create(op->getLoc(), fnName, libFnType);
- module.push_back(libFn);
- // Return after creating the function definition. The body will be created
- // later.
- return libFn;
+ auto libFnType = FunctionType::get(inputTypes, {}, rewriter.getContext());
+ // fnName is a dynamic std::String, unique it via a SymbolRefAttr.
+ SymbolRefAttr fnNameAttr = rewriter.getSymbolRefAttr(fnName);
+ OpBuilder::InsertionGuard guard(rewriter);
+ // Insert before module terminator.
+ rewriter.setInsertionPoint(module.getBody(),
+ std::prev(module.getBody()->end()));
+ return rewriter.create<FuncOp>(op->getLoc(), fnNameAttr.getValue(), libFnType,
+ ArrayRef<NamedAttribute>{});
}
namespace {
// `LinalgOp::getLibraryCallName()` function.
// The implementation of the function can be either in the same module or in an
// externally linked library.
-template <typename LinalgOp> class LinalgOpConversion : public LLVMOpLowering {
+template <typename LinalgOp>
+class LinalgOpConversion : public OpRewritePattern<LinalgOp> {
public:
- explicit LinalgOpConversion(MLIRContext *context,
- LinalgTypeConverter &lowering_)
- : LLVMOpLowering(LinalgOp::getOperationName(), context, lowering_) {}
+ using OpRewritePattern<LinalgOp>::OpRewritePattern;
- PatternMatchResult
- matchAndRewrite(Operation *op, ArrayRef<Value *> operands,
- ConversionPatternRewriter &rewriter) const override {
- auto f = getLLVMLibraryCallDeclaration<LinalgOp>(op, lowering, rewriter);
+ PatternMatchResult matchAndRewrite(LinalgOp op,
+ PatternRewriter &rewriter) const override {
+ auto f = getLLVMLibraryCallDeclaration<LinalgOp>(op, rewriter);
if (!f)
- return matchFailure();
+ return this->matchFailure();
auto fAttr = rewriter.getSymbolRefAttr(f);
- auto named = rewriter.getNamedAttr("callee", fAttr);
- rewriter.replaceOpWithNewOp<LLVM::CallOp>(
- op, promoteStructs(op->getLoc(), operands, rewriter, lowering),
- ArrayRef<NamedAttribute>{named});
- return matchSuccess();
+ SmallVector<Value *, 4> operands(op.getOperands().begin(),
+ op.getOperands().end());
+ rewriter.replaceOpWithNewOp<mlir::CallOp>(op, fAttr.getValue(),
+ ArrayRef<Type>{}, operands);
+ return this->matchSuccess();
}
};
/// Conversion pattern specialization for CopyOp. This kicks in when both input
/// and output permutations are left unspecified or are the identity.
-template <> class LinalgOpConversion<CopyOp> : public LLVMOpLowering {
+template <> class LinalgOpConversion<CopyOp> : public OpRewritePattern<CopyOp> {
public:
- explicit LinalgOpConversion(MLIRContext *context,
- LinalgTypeConverter &lowering_)
- : LLVMOpLowering(CopyOp::getOperationName(), context, lowering_) {}
+ using OpRewritePattern<CopyOp>::OpRewritePattern;
- PatternMatchResult
- matchAndRewrite(Operation *op, ArrayRef<Value *> operands,
- ConversionPatternRewriter &rewriter) const override {
- auto copyOp = cast<CopyOp>(op);
- auto inputPerm = copyOp.inputPermutation();
+ PatternMatchResult matchAndRewrite(CopyOp op,
+ PatternRewriter &rewriter) const override {
+ auto inputPerm = op.inputPermutation();
if (inputPerm.hasValue() && !inputPerm->isIdentity())
return matchFailure();
- auto outputPerm = copyOp.outputPermutation();
+ auto outputPerm = op.outputPermutation();
if (outputPerm.hasValue() && !outputPerm->isIdentity())
return matchFailure();
- auto f = getLLVMLibraryCallDeclaration<CopyOp>(op, lowering, rewriter);
+ auto f = getLLVMLibraryCallDeclaration<CopyOp>(op, rewriter);
if (!f)
return matchFailure();
auto fAttr = rewriter.getSymbolRefAttr(f);
- auto named = rewriter.getNamedAttr("callee", fAttr);
- rewriter.replaceOpWithNewOp<LLVM::CallOp>(
- op, promoteStructs(op->getLoc(), operands, rewriter, lowering),
- ArrayRef<NamedAttribute>{named});
+ SmallVector<Value *, 4> operands(op.getOperands().begin(),
+ op.getOperands().end());
+ rewriter.replaceOpWithNewOp<mlir::CallOp>(op, fAttr.getValue(),
+ ArrayRef<Type>{}, operands);
return matchSuccess();
}
};
}
};
+/// Populate the given list with patterns that convert from Linalg to Standard.
+static void
+populateLinalgToStandardConversionPatterns(OwningRewritePatternList &patterns,
+ MLIRContext *ctx) {
+ patterns.insert<CopyTransposeConversion, LinalgOpConversion<CopyOp>,
+ LinalgOpConversion<DotOp>, LinalgOpConversion<FillOp>,
+ LinalgOpConversion<MatmulOp>>(ctx);
+}
+
/// Populate the given list with patterns that convert from Linalg to LLVM.
static void
populateLinalgToLLVMConversionPatterns(LinalgTypeConverter &converter,
OwningRewritePatternList &patterns,
MLIRContext *ctx) {
- patterns.insert<CopyTransposeConversion>(ctx);
patterns.insert<BufferAllocOpConversion, BufferDeallocOpConversion,
- BufferSizeOpConversion, DimOpConversion,
- LinalgOpConversion<CopyOp>, LinalgOpConversion<DotOp>,
- LinalgOpConversion<FillOp>, LinalgOpConversion<MatmulOp>,
- LoadOpConversion, RangeOpConversion, SliceOpConversion,
- StoreOpConversion, TransposeOpConversion, ViewOpConversion>(
- ctx, converter);
+ BufferSizeOpConversion, RangeOpConversion, SliceOpConversion,
+ TransposeOpConversion, ViewOpConversion>(ctx, converter);
}
namespace {
populateAffineToStdConversionPatterns(patterns, &getContext());
populateLoopToStdConversionPatterns(patterns, &getContext());
populateStdToLLVMConversionPatterns(converter, patterns);
+ populateLinalgToStandardConversionPatterns(patterns, &getContext());
populateLinalgToLLVMConversionPatterns(converter, patterns, &getContext());
ConversionTarget target(getContext());
target.addLegalDialect<LLVM::LLVMDialect>();
target.addDynamicallyLegalOp<FuncOp>(
[&](FuncOp op) { return converter.isSignatureLegal(op.getType()); });
- if (failed(applyPartialConversion(module, target, patterns, &converter))) {
+ target.addLegalOp<ModuleOp, ModuleTerminatorOp>();
+ if (failed(applyFullConversion(module, target, patterns, &converter)))
signalPassFailure();
- }
}
std::unique_ptr<OpPassBase<ModuleOp>>
}
static PassRegistration<LowerLinalgToLLVMPass>
- pass("linalg-lower-to-llvm-dialect",
+ pass("linalg-convert-to-llvm",
"Lower the operations from the linalg dialect into the LLVM dialect");
using namespace mlir::linalg;
using namespace mlir::linalg::intrinsics;
-using IndexedLinalgValue = TemplatedIndexedValue<linalg_load, linalg_store>;
+using IndexedLinalgValue = TemplatedIndexedValue<std_load, std_store>;
using edsc::op::operator+;
using edsc::op::operator==;
};
// Emits the MLIR for the scalar part of the generic op by:
-// 1. Emitting linalg_load and linalg_store ops for each input and output
+// 1. Emitting std_load and std_store ops for each input and output
// view in order. This is achieved by applying the appropriate input or
// output map to the enclosing induction variables.
// 2. Emitting a call to `op.fun()` that takes as arguments the scalars
// from point 1. above.
-// 3. Emitting linalg_store to store the results of 2. to the output
+// 3. Emitting std_store to store the results of 2. to the output
// views.
//
// An example output may resemble:
// loop.for %i = %c0 to %0 step %c1 {
// loop.for %j = %c0 to %1 step %c1 {
// loop.for %k = %c0 to %4 step %c1 {
-// %11 = linalg.load %arg0[%i, %j] : !linalg.view<?x?xf32>
-// %12 = linalg.load %arg1[%i, %j, %k] : !linalg.view<?x?x?xf32>
-// %13 = linalg.load %arg2[%i, %k, %j] : !linalg.view<?x?x?xf32>
+// %11 = linalg.load %arg0[%i, %j] :
+// memref<?x?xf32, stride_specification>
+// %12 = linalg.load %arg1[%i, %j, %k] :
+// memref<?x?x?xf32, stride_specification>
+// %13 = linalg.load %arg2[%i, %k, %j] :
+// memref<?x?x?xf32, stride_specification>
// %14:2 = call @foo(%11, %12, %13) : (f32, f32, f32) -> (f32, f32)
-// linalg.store %14#0, %arg1[%i, %j, %k] : !linalg.view<?x?x?xf32>
-// linalg.store %14#1, %arg2[%i, %k, %j] : !linalg.view<?x?x?xf32>
+// linalg.store %14#0, %arg1[%i, %j, %k] :
+// memref<?x?x?Xf32, stride_specification>
+// linalg.store %14#1, %arg2[%i, %k, %j] :
+// memref<?x?x?Xf32, stride_specification>
// }
// }
// }
unsigned nOutputs = genericOp.getNumOutputs();
SmallVector<Value *, 4> indexedValues(nInputs + nOutputs);
- // 1.a. Emit linalg_load from input views.
+ // 1.a. Emit std_load from input views.
for (unsigned i = 0, e = nInputs; i < e; ++i) {
ValueHandleArray indexing(foldedAffineApplies(
b, loc, genericOp.getInputIndexingMap(i), allIvs, folder));
- indexedValues[i] = linalg_load(genericOp.getInput(i), indexing);
+ indexedValues[i] = std_load(genericOp.getInput(i), indexing);
}
- // 1.b. Emit linalg_load from output views.
+ // 1.b. Emit std_load from output views.
for (unsigned i = 0, e = nOutputs; i < e; ++i) {
ValueHandleArray indexing(foldedAffineApplies(
b, loc, genericOp.getOutputIndexingMap(i), allIvs, folder));
- indexedValues[nInputs + i] =
- linalg_load(genericOp.getOutput(i), indexing);
+ indexedValues[nInputs + i] = std_load(genericOp.getOutput(i), indexing);
}
auto funcOp = genericOp.getFunction();
Operation *callOp = call(funcOp, indexedValues);
assert(callOp->getNumResults() == genericOp.getNumOutputs());
- // 3. Emit linalg_store.
+ // 3. Emit std_store.
for (unsigned i = 0, e = nOutputs; i < e; ++i) {
ValueHandleArray indexing(foldedAffineApplies(
b, loc, genericOp.getOutputIndexingMap(i), allIvs, folder));
- linalg_store(callOp->getResult(i), genericOp.getOutput(i), indexing);
+ std_store(callOp->getResult(i), genericOp.getOutput(i), indexing);
}
} else {
// TODO(ntv): When a region inliner exists, use it.
map.map(std::get<0>(it), std::get<1>(it));
}
- // 3. Emit linalg_store.
+ // 3. Emit std_store.
auto *yieldOp = cast<YieldOp>(block.back()).getOperation();
assert(yieldOp->getNumOperands() == nOutputs);
for (unsigned i = 0, e = nOutputs; i < e; ++i) {
ValueHandleArray indexing(foldedAffineApplies(
b, loc, genericOp.getOutputIndexingMap(i), allIvs, folder));
- linalg_store(map.lookup(yieldOp->getOperand(i)), genericOp.getOutput(i),
- indexing);
+ std_store(map.lookup(yieldOp->getOperand(i)), genericOp.getOutput(i),
+ indexing);
}
}
}
for (unsigned viewIndex = 0; viewIndex < linalgOp.getNumInputsAndOutputs();
++viewIndex) {
Value *view = *(viewIteratorBegin + viewIndex);
- unsigned viewRank = view->getType().cast<ViewType>().getRank();
+ unsigned rank = view->getType().cast<MemRefType>().getRank();
auto map = loopToOperandRangesMaps(linalgOp)[viewIndex];
// If the view is not tiled, we can use it as is.
if (!isTiled(map, tileSizes)) {
// Construct a new subview for the tile.
SmallVector<SubViewOp::Range, 4> subViewOperands;
- subViewOperands.reserve(viewRank * 3);
- for (unsigned r = 0; r < viewRank; ++r) {
+ subViewOperands.reserve(rank * 3);
+ for (unsigned r = 0; r < rank; ++r) {
if (!isTiled(map.getSubMap({r}), tileSizes)) {
- subViewOperands.push_back(SubViewOp::Range{
- constant_index(folder, 0), linalg::intrinsics::dim(view, r),
- constant_index(folder, 1)});
+ subViewOperands.push_back(SubViewOp::Range{constant_index(folder, 0),
+ dim(view, r),
+ constant_index(folder, 1)});
continue;
}
auto rank = en.index();
auto rangeValue = en.value();
Value *d =
- isa<linalg::DimOp>(rangeValue.max->getDefiningOp())
+ isa<DimOp>(rangeValue.max->getDefiningOp())
? rangeValue.max
: applyMapToValues(b, loc, getAffineDifferenceMap(b.getContext()),
{rangeValue.max, rangeValue.min}, folder)
.front();
allocSize = muli(folder, allocSize, d).getValue();
fullRanges.push_back(range(folder, zero, d, one));
- partialRanges.push_back(
- range(folder, zero, linalg::intrinsics::dim(subView, rank), one));
+ partialRanges.push_back(range(folder, zero, dim(subView, rank), one));
}
auto *buffer = allocBuffer(viewType.getElementType(), allocSize);
auto fullLocalView = view(buffer, fullRanges);
auto zero = constant_index(folder, 0);
auto one = constant_index(folder, 1);
- auto viewType = v->getType().cast<ViewType>();
+ auto viewType = v->getType().cast<MemRefType>();
auto rank = viewType.getRank();
Value *allocSize = one;
SmallVector<Value *, 8> partialRanges;
partialRanges.reserve(rank);
for (unsigned r = 0; r < rank; ++r) {
- Value *d = linalg::intrinsics::dim(v, r);
+ Value *d = dim(v, r);
allocSize = muli(folder, allocSize, d).getValue();
partialRanges.push_back(range(folder, zero, d, one));
}
auto info = promotionInfo.find(v);
if (info == promotionInfo.end())
continue;
- auto viewType = v->getType().cast<ViewType>();
+ auto viewType = v->getType().cast<MemRefType>();
// TODO(ntv): value to fill with should be related to the operation.
// For now, just use APFloat(0.0f).
auto t = viewType.getElementType().cast<FloatType>();
strides[pos] += val;
}
+// This sums multiple offsets as they are seen. In the particular case of
+// accumulating a dynamic offset with either a static of dynamic one, this
+// saturates to MemRefType::kDynamicStrideOrOffset.
+static void accumulateOffset(int64_t &offset, bool &seenOffset, int64_t val) {
+ if (!seenOffset) {
+ // Newly seen case, sets value
+ offset = val;
+ seenOffset = true;
+ return;
+ }
+ if (offset != MemRefType::kDynamicStrideOrOffset)
+ // Already seen case accumulates unless they are already saturated.
+ offset += val;
+}
+
/// Takes a single AffineExpr `e` and populates the `strides` and `seen` arrays
/// with the strides values for each dim position and whether a value exists at
/// that position, respectively.
/// The convention is that the strides for dimensions d0, .. dn appear in
-/// order followed by the constant offset, to make indexing intuitive into the
-/// result.
+/// order to make indexing intuitive into the result.
static void extractStrides(AffineExpr e, MutableArrayRef<int64_t> strides,
- MutableArrayRef<bool> seen, bool &failed) {
+ int64_t &offset, MutableArrayRef<bool> seen,
+ bool &seenOffset, bool &failed) {
auto bin = e.dyn_cast<AffineBinaryOpExpr>();
if (!bin)
return;
for (auto e : {bin.getLHS(), bin.getRHS()}) {
if (auto cst = e.dyn_cast<AffineConstantExpr>()) {
// Independent constants cumulate.
- accumulateStrides(strides, seen, seen.size() - 1, cst.getValue());
+ accumulateOffset(offset, seenOffset, cst.getValue());
} else if (auto sym = e.dyn_cast<AffineSymbolExpr>()) {
// Independent symbols saturate.
- strides.back() = MemRefType::kDynamicStrideOrOffset;
- seen.back() = true;
+ offset = MemRefType::kDynamicStrideOrOffset;
+ seenOffset = true;
} else if (auto dim = e.dyn_cast<AffineDimExpr>()) {
// Independent symbols cumulate 1.
accumulateStrides(strides, seen, dim.getPosition(), 1);
llvm_unreachable("unexpected binary operation");
}
-// Fallback cases for terminal dim/sym/cst that are not part of a binary op
-// (i.e. single term).
+// Fallback cases for terminal dim/sym/cst that are not part of a binary op (
+// i.e. single term).
static void extractStridesFromTerm(AffineExpr e,
MutableArrayRef<int64_t> strides,
- MutableArrayRef<bool> seen) {
+ int64_t &offset, MutableArrayRef<bool> seen,
+ bool &seenOffset) {
if (auto cst = e.dyn_cast<AffineConstantExpr>()) {
- assert(!seen.back() && "unexpected `seen` bit with single term");
- strides.back() = cst.getValue();
- seen.back() = true;
+ assert(!seenOffset && "unexpected `seen` bit with single term");
+ offset = cst.getValue();
+ seenOffset = true;
return;
}
if (auto sym = e.dyn_cast<AffineSymbolExpr>()) {
- assert(!seen.back() && "unexpected `seen` bit with single term");
- strides.back() = MemRefType::kDynamicStrideOrOffset;
- seen.back() = true;
+ assert(!seenOffset && "unexpected `seen` bit with single term");
+ offset = MemRefType::kDynamicStrideOrOffset;
+ seenOffset = true;
return;
}
if (auto dim = e.dyn_cast<AffineDimExpr>()) {
- assert(!seen.back() && "unexpected `seen` bit with single term");
+ assert(!seen[dim.getPosition()] &&
+ "unexpected `seen` bit with single term");
strides[dim.getPosition()] = 1;
seen[dim.getPosition()] = true;
return;
llvm_unreachable("unexpected binary operation");
}
-LogicalResult
-MemRefType::getStridesAndOffset(SmallVectorImpl<int64_t> &strides) const {
+LogicalResult MemRefType::getStridesAndOffset(SmallVectorImpl<int64_t> &strides,
+ int64_t &offset) const {
auto affineMaps = getAffineMaps();
// For now strides are only computed on a single affine map with a single
// result (i.e. the closed subset of linearization maps that are compatible
if (affineMaps.empty() || affineMaps[0].isIdentity()) {
if (getRank() == 0) {
// Handle 0-D corner case.
- strides.push_back(0);
+ offset = 0;
return success();
}
stridedExpr = makeCanonicalStridedLayoutExpr(getShape(), getContext());
return failure();
bool failed = false;
- strides = SmallVector<int64_t, 4>(getRank() + 1, 0);
- SmallVector<bool, 4> seen(getRank() + 1, false);
+ strides = SmallVector<int64_t, 4>(getRank(), 0);
+ bool seenOffset = false;
+ SmallVector<bool, 4> seen(getRank(), false);
if (stridedExpr.isa<AffineBinaryOpExpr>()) {
stridedExpr.walk([&](AffineExpr e) {
if (!failed)
- extractStrides(e, strides, seen, failed);
+ extractStrides(e, strides, offset, seen, seenOffset, failed);
});
} else {
- extractStridesFromTerm(stridedExpr, strides, seen);
+ extractStridesFromTerm(stridedExpr, strides, offset, seen, seenOffset);
}
// Constant offset may not be present in `stridedExpr` which means it is
// implicitly 0.
- if (!seen.back()) {
- seen.back() = true;
- strides.back() = 0;
- }
+ if (!seenOffset)
+ offset = 0;
+
if (failed || !llvm::all_of(seen, [](bool b) { return b; })) {
strides.clear();
return failure();
}
+
return success();
}
/// Return the number of element types.
size_t TupleType::size() const { return getImpl()->size(); }
+
+AffineMap mlir::makeStridedLinearLayoutMap(ArrayRef<int64_t> strides,
+ int64_t offset,
+ MLIRContext *context) {
+ AffineExpr expr;
+ unsigned nSymbols = 0;
+
+ // AffineExpr for offset.
+ // Static case.
+ if (offset != MemRefType::kDynamicStrideOrOffset) {
+ auto cst = getAffineConstantExpr(offset, context);
+ expr = cst;
+ } else {
+ // Dynamic case, new symbol for the offset.
+ auto sym = getAffineSymbolExpr(nSymbols++, context);
+ expr = sym;
+ }
+
+ // AffineExpr for strides.
+ for (auto en : llvm::enumerate(strides)) {
+ auto dim = en.index();
+ auto stride = en.value();
+ assert(stride != 0 && "Invalid stride specification");
+ auto d = getAffineDimExpr(dim, context);
+ AffineExpr mult;
+ // Static case.
+ if (stride != MemRefType::kDynamicStrideOrOffset)
+ mult = getAffineConstantExpr(stride, context);
+ else
+ // Dynamic case, new symbol for each new stride.
+ mult = getAffineSymbolExpr(nSymbols++, context);
+ expr = expr + d * mult;
+ }
+
+ return AffineMap::get(strides.size(), nSymbols, expr);
+}
+
+bool mlir::isStrided(MemRefType t) {
+ int64_t offset;
+ SmallVector<int64_t, 4> stridesAndOffset;
+ auto res = t.getStridesAndOffset(stridesAndOffset, offset);
+ return succeeded(res);
+}
+++ /dev/null
-// RUN: mlir-opt %s -canonicalize | FileCheck %s
-
-// CHECK-DAG: #[[SUB:.*]] = ()[s0, s1] -> (s0 - s1)
-
-func @fold_constants(%arg0: !linalg.buffer<?xf32>) -> (index, index, index, index, index) {
- %c0 = constant 0 : index
- %c1 = constant 1 : index
- %c2 = constant 2 : index
- %c3 = constant 3 : index
- %c4 = constant 4 : index
- %c5 = constant 5 : index
- %R02 = linalg.range %c0:%c2:%c1 : !linalg.range
- %R03 = linalg.range %c0:%c3:%c1 : !linalg.range
- %R04 = linalg.range %c0:%c4:%c1 : !linalg.range
- %R12 = linalg.range %c1:%c2:%c1 : !linalg.range
- %R13 = linalg.range %c1:%c3:%c1 : !linalg.range
- %R14 = linalg.range %c1:%c4:%c1 : !linalg.range
-
- %v = linalg.view %arg0[%R02, %R14] : !linalg.buffer<?xf32> -> !linalg.view<?x?xf32>
- // Expected 2.
- %v0 = linalg.dim %v, 0 : !linalg.view<?x?xf32>
- // Expected 3.
- %v1 = linalg.dim %v, 1 : !linalg.view<?x?xf32>
-
- %s = linalg.slice %v[%c1, %R12] : !linalg.view<?x?xf32>, index, !linalg.range, !linalg.view<?xf32>
- // Expected 1.
- %s0 = linalg.dim %s, 0 : !linalg.view<?xf32>
-
- %sv = linalg.subview %v[%v0, %v1, %c1, %c2, %c4, %c1] : !linalg.view<?x?xf32>
- // Expected 1.
- %sv0 = linalg.dim %sv, 0 : !linalg.view<?x?xf32>
- // Expected 2.
- %sv1 = linalg.dim %sv, 1 : !linalg.view<?x?xf32>
-
- return %v0, %v1, %s0, %sv0, %sv1 : index, index, index, index, index
-}
-
-// CHECK-LABEL: fold_constants
-// CHECK-DAG: %[[c1:.*]] = constant 1 : index
-// CHECK-DAG: %[[c2:.*]] = constant 2 : index
-// CHECK-DAG: %[[c3:.*]] = constant 3 : index
-// CHECK: return %[[c2]], %[[c3]], %[[c1]], %[[c1]], %[[c2]]
-
-
-func @fold_indices(%arg0: !linalg.buffer<?xf32>, %arg1: index, %arg2: index, %arg3: index) -> (index, index, index, index) {
- %c0 = constant 0 : index
- %c1 = constant 1 : index
- %R = linalg.range %arg1:%arg3:%c1 : !linalg.range
-
- %v = linalg.view %arg0[%R, %R] : !linalg.buffer<?xf32> -> !linalg.view<?x?xf32>
- // Expected %arg3 - %arg1.
- %v0 = linalg.dim %v, 0 : !linalg.view<?x?xf32>
- // Expected %arg3 - %arg1.
- %v1 = linalg.dim %v, 1 : !linalg.view<?x?xf32>
-
- %arg1_p_arg2 = addi %arg1, %arg2: index
- %arg1_p_arg2_affine = affine.apply (i, j) -> (i + j) (%arg1, %arg2)
- %sv = linalg.subview %v[%arg1, %arg1_p_arg2, %c1, %arg1, %arg1_p_arg2_affine, %c1] : !linalg.view<?x?xf32>
- // Expected %arg2 but can't fold affine.apply with addi.
- %sv0 = linalg.dim %sv, 0 : !linalg.view<?x?xf32>
- // Expected %arg2.
- %sv1 = linalg.dim %sv, 1 : !linalg.view<?x?xf32>
-
- return %v0, %v1, %sv0, %sv1 : index, index, index, index
-}
-
-// CHECK-LABEL: fold_indices
-// CHECK: (%[[arg0:.*]]: !linalg.buffer<?xf32>, %[[arg1:.*]]: index, %[[arg2:.*]]: index, %[[arg3:.*]]: index
-// CHECK: %[[r0:.*]] = affine.apply #[[SUB]]()[%[[arg3]], %[[arg1]]]
-// CHECK: %[[r1:.*]] = affine.apply #[[SUB]]()[%[[arg3]], %[[arg1]]]
-// CHECK: %[[add:.*]] = addi %[[arg1]], %[[arg2]] : index
-// CHECK: %[[aff:.*]] = affine.apply #[[SUB]]()[%[[add]], %[[arg1]]]
-// CHECK: return %[[r0]], %[[r1]], %[[aff]], %[[arg2]]
\ No newline at end of file
// RUN: mlir-opt %s -linalg-fusion | FileCheck %s
+
#map0 = (d0) -> (d0 + 20)
#map1 = (d0) -> (d0 + 40)
#map2 = (d0) -> (d0 + 30)
#map3 = (d0) -> (d0 + 2)
#map4 = (d0) -> (d0 + 4)
#map5 = (d0) -> (d0 + 3)
-func @f1(%A: !linalg.view<?x?xf32>, %B: !linalg.view<?x?xf32>, %C: !linalg.view<?x?xf32>, %D: !linalg.view<?x?xf32>, %E: !linalg.view<?x?xf32>) -> !linalg.view<?x?xf32> {
+
+// CHECK-DAG: #[[strided2D:.*]] = (d0, d1)[s0, s1] -> (d0 * s1 + s0 + d1)
+#strided2D = (d0, d1)[s0, s1] -> (d0 * s1 + s0 + d1)
+
+func @f1(%A: memref<?x?xf32, #strided2D>, %B: memref<?x?xf32, #strided2D>, %C: memref<?x?xf32, #strided2D>, %D: memref<?x?xf32, #strided2D>, %E: memref<?x?xf32, #strided2D>) -> memref<?x?xf32, #strided2D> {
%c1 = constant 1 : index
%c0 = constant 0 : index
%c4 = constant 4 : index
%c40 = constant 40 : index
%c30 = constant 30 : index
%c20 = constant 20 : index
- %0 = linalg.dim %C, 0 : !linalg.view<?x?xf32>
- %1 = linalg.dim %C, 1 : !linalg.view<?x?xf32>
- %2 = linalg.dim %D, 1 : !linalg.view<?x?xf32>
- linalg.matmul(%A, %B, %C) : !linalg.view<?x?xf32>, !linalg.view<?x?xf32>, !linalg.view<?x?xf32>
+ %0 = dim %C, 0 : memref<?x?xf32, #strided2D>
+ %1 = dim %C, 1 : memref<?x?xf32, #strided2D>
+ %2 = dim %D, 1 : memref<?x?xf32, #strided2D>
+ linalg.matmul(%A, %B, %C) : memref<?x?xf32, #strided2D>, memref<?x?xf32, #strided2D>, memref<?x?xf32, #strided2D>
loop.for %arg5 = %c0 to %0 step %c20 {
loop.for %arg6 = %c0 to %2 step %c30 {
loop.for %arg7 = %c0 to %1 step %c40 {
%3 = affine.apply #map0(%arg5)
%4 = affine.apply #map1(%arg7)
- %5 = linalg.subview %C[%arg5, %3, %c1, %arg7, %4, %c1] : !linalg.view<?x?xf32>
+ %5 = linalg.subview %C[%arg5, %3, %c1, %arg7, %4, %c1] : memref<?x?xf32, #strided2D>
%6 = affine.apply #map2(%arg6)
- %7 = linalg.subview %D[%arg7, %4, %c1, %arg6, %6, %c1] : !linalg.view<?x?xf32>
- %8 = linalg.subview %E[%arg5, %3, %c1, %arg6, %6, %c1] : !linalg.view<?x?xf32>
- %9 = linalg.dim %5, 0 : !linalg.view<?x?xf32>
- %10 = linalg.dim %5, 1 : !linalg.view<?x?xf32>
- %11 = linalg.dim %7, 1 : !linalg.view<?x?xf32>
+ %7 = linalg.subview %D[%arg7, %4, %c1, %arg6, %6, %c1] : memref<?x?xf32, #strided2D>
+ %8 = linalg.subview %E[%arg5, %3, %c1, %arg6, %6, %c1] : memref<?x?xf32, #strided2D>
+ %9 = dim %5, 0 : memref<?x?xf32, #strided2D>
+ %10 = dim %5, 1 : memref<?x?xf32, #strided2D>
+ %11 = dim %7, 1 : memref<?x?xf32, #strided2D>
loop.for %arg8 = %c0 to %9 step %c2 {
loop.for %arg9 = %c0 to %11 step %c3 {
loop.for %B0 = %c0 to %10 step %c4 {
%12 = affine.apply #map3(%arg8)
%13 = affine.apply #map4(%B0)
- %14 = linalg.subview %5[%arg8, %12, %c1, %B0, %13, %c1] : !linalg.view<?x?xf32>
+ %14 = linalg.subview %5[%arg8, %12, %c1, %B0, %13, %c1] : memref<?x?xf32, #strided2D>
%15 = affine.apply #map5(%arg9)
- %16 = linalg.subview %7[%B0, %13, %c1, %arg9, %15, %c1] : !linalg.view<?x?xf32>
- %17 = linalg.subview %8[%arg8, %12, %c1, %arg9, %15, %c1] : !linalg.view<?x?xf32>
- linalg.matmul(%14, %16, %17) : !linalg.view<?x?xf32>, !linalg.view<?x?xf32>, !linalg.view<?x?xf32>
+ %16 = linalg.subview %7[%B0, %13, %c1, %arg9, %15, %c1] : memref<?x?xf32, #strided2D>
+ %17 = linalg.subview %8[%arg8, %12, %c1, %arg9, %15, %c1] : memref<?x?xf32, #strided2D>
+ linalg.matmul(%14, %16, %17) : memref<?x?xf32, #strided2D>, memref<?x?xf32, #strided2D>, memref<?x?xf32, #strided2D>
}
}
}
}
}
}
- return %E : !linalg.view<?x?xf32>
+ return %E : memref<?x?xf32, #strided2D>
}
// CHECK-LABEL: func @f1
// CHECK: (%[[A:.*]]:{{.*}}, %[[B:.*]]:{{.*}}, %[[C:.*]]:{{.*}}, %[[D:.*]]:{{.*}}, %[[E:.*]]:{{.*}})
#map1 = (d0) -> (d0 + 4)
#map2 = (d0) -> (d0 + 3)
-func @f1(%A: !linalg.view<?x?xf32>, %B: !linalg.view<?x?xf32>, %C: !linalg.view<?x?xf32>, %D: !linalg.view<?x?xf32>, %E: !linalg.view<?x?xf32>) -> !linalg.view<?x?xf32> {
+// CHECK-DAG: #[[strided2D:.*]] = (d0, d1)[s0, s1] -> (d0 * s1 + s0 + d1)
+#strided2D = (d0, d1)[s0, s1] -> (d0 * s1 + s0 + d1)
+
+func @f1(%A: memref<?x?xf32, #strided2D>, %B: memref<?x?xf32, #strided2D>, %C: memref<?x?xf32, #strided2D>, %D: memref<?x?xf32, #strided2D>, %E: memref<?x?xf32, #strided2D>) -> memref<?x?xf32, #strided2D> {
%c0 = constant 0 : index
%c4 = constant 4 : index
%c3 = constant 3 : index
%c2 = constant 2 : index
- %0 = linalg.dim %A, 0 : !linalg.view<?x?xf32>
- %1 = linalg.dim %A, 1 : !linalg.view<?x?xf32>
- %2 = linalg.dim %B, 1 : !linalg.view<?x?xf32>
- linalg.matmul(%A, %B, %C) : !linalg.view<?x?xf32>, !linalg.view<?x?xf32>, !linalg.view<?x?xf32>
+ %0 = dim %A, 0 : memref<?x?xf32, #strided2D>
+ %1 = dim %A, 1 : memref<?x?xf32, #strided2D>
+ %2 = dim %B, 1 : memref<?x?xf32, #strided2D>
+ linalg.matmul(%A, %B, %C) : memref<?x?xf32, #strided2D>, memref<?x?xf32, #strided2D>, memref<?x?xf32, #strided2D>
%c1 = constant 1 : index
loop.for %arg5 = %c0 to %0 step %c2 {
loop.for %arg6 = %c0 to %2 step %c3 {
loop.for %arg7 = %c0 to %1 step %c4 {
%3 = affine.apply #map0(%arg5)
%4 = affine.apply #map1(%arg7)
- %5 = linalg.subview %A[%arg5, %3, %c1, %arg7, %4, %c1] : !linalg.view<?x?xf32>
+ %5 = linalg.subview %A[%arg5, %3, %c1, %arg7, %4, %c1] : memref<?x?xf32, #strided2D>
%6 = affine.apply #map2(%arg6)
- %7 = linalg.subview %B[%arg7, %4, %c1, %arg6, %6, %c1] : !linalg.view<?x?xf32>
- %8 = linalg.subview %C[%arg5, %3, %c1, %arg6, %6, %c1] : !linalg.view<?x?xf32>
- linalg.matmul(%5, %7, %8) : !linalg.view<?x?xf32>, !linalg.view<?x?xf32>, !linalg.view<?x?xf32>
+ %7 = linalg.subview %B[%arg7, %4, %c1, %arg6, %6, %c1] : memref<?x?xf32, #strided2D>
+ %8 = linalg.subview %C[%arg5, %3, %c1, %arg6, %6, %c1] : memref<?x?xf32, #strided2D>
+ linalg.matmul(%5, %7, %8) : memref<?x?xf32, #strided2D>, memref<?x?xf32, #strided2D>, memref<?x?xf32, #strided2D>
}
}
}
- return %E : !linalg.view<?x?xf32>
+ return %E : memref<?x?xf32, #strided2D>
}
// CHECK-LABEL: func @f1
// CHECK: (%[[A:.*]]:{{.*}}, %[[B:.*]]:{{.*}}, %[[C:.*]]:{{.*}}, %[[D:.*]]:{{.*}}, %[[E:.*]]:{{.*}})
// CHECK: loop.for
// CHECK: linalg.matmul
-func @f2(%A: !linalg.view<?x?xf32>, %B: !linalg.view<?x?xf32>, %C: !linalg.view<?x?xf32>, %D: !linalg.view<?x?xf32>, %E: !linalg.view<?x?xf32>) -> !linalg.view<?x?xf32> {
+func @f2(%A: memref<?x?xf32, #strided2D>, %B: memref<?x?xf32, #strided2D>, %C: memref<?x?xf32, #strided2D>, %D: memref<?x?xf32, #strided2D>, %E: memref<?x?xf32, #strided2D>) -> memref<?x?xf32, #strided2D> {
%c1 = constant 1 : index
%c0 = constant 0 : index
%c4 = constant 4 : index
%c3 = constant 3 : index
%c2 = constant 2 : index
- linalg.matmul(%A, %B, %C) : !linalg.view<?x?xf32>, !linalg.view<?x?xf32>, !linalg.view<?x?xf32>
- %0 = linalg.dim %C, 0 : !linalg.view<?x?xf32>
- %1 = linalg.dim %C, 1 : !linalg.view<?x?xf32>
- %2 = linalg.dim %D, 1 : !linalg.view<?x?xf32>
+ linalg.matmul(%A, %B, %C) : memref<?x?xf32, #strided2D>, memref<?x?xf32, #strided2D>, memref<?x?xf32, #strided2D>
+ %0 = dim %C, 0 : memref<?x?xf32, #strided2D>
+ %1 = dim %C, 1 : memref<?x?xf32, #strided2D>
+ %2 = dim %D, 1 : memref<?x?xf32, #strided2D>
loop.for %arg5 = %c0 to %0 step %c2 {
loop.for %arg6 = %c0 to %2 step %c3 {
loop.for %arg7 = %c0 to %1 step %c4 {
%3 = affine.apply #map0(%arg5)
%4 = affine.apply #map1(%arg7)
- %5 = linalg.subview %C[%arg5, %3, %c1, %arg7, %4, %c1] : !linalg.view<?x?xf32>
+ %5 = linalg.subview %C[%arg5, %3, %c1, %arg7, %4, %c1] : memref<?x?xf32, #strided2D>
%6 = affine.apply #map2(%arg6)
- %7 = linalg.subview %D[%arg7, %4, %c1, %arg6, %6, %c1] : !linalg.view<?x?xf32>
- %8 = linalg.subview %E[%arg5, %3, %c1, %arg6, %6, %c1] : !linalg.view<?x?xf32>
- linalg.matmul(%5, %7, %8) : !linalg.view<?x?xf32>, !linalg.view<?x?xf32>, !linalg.view<?x?xf32>
+ %7 = linalg.subview %D[%arg7, %4, %c1, %arg6, %6, %c1] : memref<?x?xf32, #strided2D>
+ %8 = linalg.subview %E[%arg5, %3, %c1, %arg6, %6, %c1] : memref<?x?xf32, #strided2D>
+ linalg.matmul(%5, %7, %8) : memref<?x?xf32, #strided2D>, memref<?x?xf32, #strided2D>, memref<?x?xf32, #strided2D>
}
}
}
- return %E : !linalg.view<?x?xf32>
+ return %E : memref<?x?xf32, #strided2D>
}
// CHECK-LABEL: func @f2
// CHECK: (%[[A:.*]]:{{.*}}, %[[B:.*]]:{{.*}}, %[[C:.*]]:{{.*}}, %[[D:.*]]:{{.*}}, %[[E:.*]]:{{.*}})
-// CHECK-DAG: %[[C_0:.*]] = linalg.dim %[[C]], 0 : !linalg.view<?x?xf32>
-// CHECK-DAG: %[[C_1:.*]] = linalg.dim %[[C]], 1 : !linalg.view<?x?xf32>
-// CHECK-DAG: %[[D_1:.*]] = linalg.dim %[[D]], 1 : !linalg.view<?x?xf32>
+// CHECK-DAG: %[[C_0:.*]] = dim %[[C]], 0 : memref<?x?xf32, #[[strided2D]]>
+// CHECK-DAG: %[[C_1:.*]] = dim %[[C]], 1 : memref<?x?xf32, #[[strided2D]]>
+// CHECK-DAG: %[[D_1:.*]] = dim %[[D]], 1 : memref<?x?xf32, #[[strided2D]]>
// CHECK: loop.for %{{.*}} = %{{.*}} to %[[C_0]] step %{{.*}} {
// CHECK: loop.for %{{.*}} = %{{.*}} to %[[D_1]] step %{{.*}} {
// CHECK: loop.for %{{.*}} = %{{.*}} to %[[C_1]] step %{{.*}} {
// CHECK: linalg.matmul
// CHECK: linalg.matmul
-func @f3(%A: !linalg.view<?x?xf32>, %B: !linalg.view<?x?xf32>, %C: !linalg.view<?x?xf32>, %D: !linalg.view<?x?xf32>, %E: !linalg.view<?x?xf32>) -> !linalg.view<?x?xf32> {
+func @f3(%A: memref<?x?xf32, #strided2D>, %B: memref<?x?xf32, #strided2D>, %C: memref<?x?xf32, #strided2D>, %D: memref<?x?xf32, #strided2D>, %E: memref<?x?xf32, #strided2D>) -> memref<?x?xf32, #strided2D> {
%c1 = constant 1 : index
%c0 = constant 0 : index
%c4 = constant 4 : index
%c3 = constant 3 : index
%c2 = constant 2 : index
- linalg.matmul(%A, %B, %C) : !linalg.view<?x?xf32>, !linalg.view<?x?xf32>, !linalg.view<?x?xf32>
- %0 = linalg.dim %D, 0 : !linalg.view<?x?xf32>
- %1 = linalg.dim %D, 1 : !linalg.view<?x?xf32>
- %2 = linalg.dim %C, 1 : !linalg.view<?x?xf32>
+ linalg.matmul(%A, %B, %C) : memref<?x?xf32, #strided2D>, memref<?x?xf32, #strided2D>, memref<?x?xf32, #strided2D>
+ %0 = dim %D, 0 : memref<?x?xf32, #strided2D>
+ %1 = dim %D, 1 : memref<?x?xf32, #strided2D>
+ %2 = dim %C, 1 : memref<?x?xf32, #strided2D>
loop.for %arg5 = %c0 to %0 step %c2 {
loop.for %arg6 = %c0 to %2 step %c3 {
loop.for %arg7 = %c0 to %1 step %c4 {
%3 = affine.apply #map0(%arg5)
%4 = affine.apply #map1(%arg7)
- %5 = linalg.subview %D[%arg5, %3, %c1, %arg7, %4, %c1] : !linalg.view<?x?xf32>
+ %5 = linalg.subview %D[%arg5, %3, %c1, %arg7, %4, %c1] : memref<?x?xf32, #strided2D>
%6 = affine.apply #map2(%arg6)
- %7 = linalg.subview %C[%arg7, %4, %c1, %arg6, %6, %c1] : !linalg.view<?x?xf32>
- %8 = linalg.subview %E[%arg5, %3, %c1, %arg6, %6, %c1] : !linalg.view<?x?xf32>
- linalg.matmul(%5, %7, %8) : !linalg.view<?x?xf32>, !linalg.view<?x?xf32>, !linalg.view<?x?xf32>
+ %7 = linalg.subview %C[%arg7, %4, %c1, %arg6, %6, %c1] : memref<?x?xf32, #strided2D>
+ %8 = linalg.subview %E[%arg5, %3, %c1, %arg6, %6, %c1] : memref<?x?xf32, #strided2D>
+ linalg.matmul(%5, %7, %8) : memref<?x?xf32, #strided2D>, memref<?x?xf32, #strided2D>, memref<?x?xf32, #strided2D>
}
}
}
- return %E : !linalg.view<?x?xf32>
+ return %E : memref<?x?xf32, #strided2D>
}
// CHECK-LABEL: func @f3
// CHECK: (%[[A:.*]]:{{.*}}, %[[B:.*]]:{{.*}}, %[[C:.*]]:{{.*}}, %[[D:.*]]:{{.*}}, %[[E:.*]]:{{.*}})
-// CHECK: %[[D_0:.*]] = linalg.dim %[[D]], 0 : !linalg.view<?x?xf32>
-// CHECK: %[[D_1:.*]] = linalg.dim %[[D]], 1 : !linalg.view<?x?xf32>
-// CHECK: %[[C_1:.*]] = linalg.dim %[[C]], 1 : !linalg.view<?x?xf32>
+// CHECK: %[[D_0:.*]] = dim %[[D]], 0 : memref<?x?xf32, #[[strided2D]]>
+// CHECK: %[[D_1:.*]] = dim %[[D]], 1 : memref<?x?xf32, #[[strided2D]]>
+// CHECK: %[[C_1:.*]] = dim %[[C]], 1 : memref<?x?xf32, #[[strided2D]]>
// CHECK: loop.for %{{.*}} = %{{.*}} to %[[D_0]] step %{{.*}} {
// CHECK: loop.for %{{.*}} = %{{.*}} to %[[C_1]] step %{{.*}} {
// CHECK: loop.for %{{.*}} = %{{.*}} to %[[D_1]] step %{{.*}} {
// CHECK: linalg.matmul
// CHECK: linalg.matmul
-func @f4(%A: !linalg.view<?x?xf32>, %B: !linalg.view<?x?xf32>, %C: !linalg.view<?x?xf32>, %D: !linalg.view<?x?xf32>, %E: !linalg.view<?x?xf32>) -> !linalg.view<?x?xf32> {
+func @f4(%A: memref<?x?xf32, #strided2D>, %B: memref<?x?xf32, #strided2D>, %C: memref<?x?xf32, #strided2D>, %D: memref<?x?xf32, #strided2D>, %E: memref<?x?xf32, #strided2D>) -> memref<?x?xf32, #strided2D> {
%c1 = constant 1 : index
%c0 = constant 0 : index
%c4 = constant 4 : index
%c3 = constant 3 : index
%c2 = constant 2 : index
- linalg.matmul(%A, %B, %C) : !linalg.view<?x?xf32>, !linalg.view<?x?xf32>, !linalg.view<?x?xf32>
- linalg.matmul(%A, %B, %D) : !linalg.view<?x?xf32>, !linalg.view<?x?xf32>, !linalg.view<?x?xf32>
- %0 = linalg.dim %C, 0 : !linalg.view<?x?xf32>
- %1 = linalg.dim %C, 1 : !linalg.view<?x?xf32>
- %2 = linalg.dim %D, 1 : !linalg.view<?x?xf32>
+ linalg.matmul(%A, %B, %C) : memref<?x?xf32, #strided2D>, memref<?x?xf32, #strided2D>, memref<?x?xf32, #strided2D>
+ linalg.matmul(%A, %B, %D) : memref<?x?xf32, #strided2D>, memref<?x?xf32, #strided2D>, memref<?x?xf32, #strided2D>
+ %0 = dim %C, 0 : memref<?x?xf32, #strided2D>
+ %1 = dim %C, 1 : memref<?x?xf32, #strided2D>
+ %2 = dim %D, 1 : memref<?x?xf32, #strided2D>
loop.for %arg5 = %c0 to %0 step %c2 {
loop.for %arg6 = %c0 to %2 step %c3 {
loop.for %arg7 = %c0 to %1 step %c4 {
%3 = affine.apply #map0(%arg5)
%4 = affine.apply #map1(%arg7)
- %5 = linalg.subview %C[%arg5, %3, %c1, %arg7, %4, %c1] : !linalg.view<?x?xf32>
+ %5 = linalg.subview %C[%arg5, %3, %c1, %arg7, %4, %c1] : memref<?x?xf32, #strided2D>
%6 = affine.apply #map2(%arg6)
- %7 = linalg.subview %D[%arg7, %4, %c1, %arg6, %6, %c1] : !linalg.view<?x?xf32>
- %8 = linalg.subview %E[%arg5, %3, %c1, %arg6, %6, %c1] : !linalg.view<?x?xf32>
- linalg.matmul(%5, %7, %8) : !linalg.view<?x?xf32>, !linalg.view<?x?xf32>, !linalg.view<?x?xf32>
+ %7 = linalg.subview %D[%arg7, %4, %c1, %arg6, %6, %c1] : memref<?x?xf32, #strided2D>
+ %8 = linalg.subview %E[%arg5, %3, %c1, %arg6, %6, %c1] : memref<?x?xf32, #strided2D>
+ linalg.matmul(%5, %7, %8) : memref<?x?xf32, #strided2D>, memref<?x?xf32, #strided2D>, memref<?x?xf32, #strided2D>
}
}
}
- return %E : !linalg.view<?x?xf32>
+ return %E : memref<?x?xf32, #strided2D>
}
// CHECK-LABEL: func @f4
// CHECK: (%[[A:.*]]:{{.*}}, %[[B:.*]]:{{.*}}, %[[C:.*]]:{{.*}}, %[[D:.*]]:{{.*}}, %[[E:.*]]:{{.*}})
-// CHECK: %[[C_0:.*]] = linalg.dim %[[C]], 0 : !linalg.view<?x?xf32>
-// CHECK: %[[C_1:.*]] = linalg.dim %[[C]], 1 : !linalg.view<?x?xf32>
-// CHECK: %[[D_1:.*]] = linalg.dim %[[D]], 1 : !linalg.view<?x?xf32>
+// CHECK: %[[C_0:.*]] = dim %[[C]], 0 : memref<?x?xf32, #[[strided2D]]>
+// CHECK: %[[C_1:.*]] = dim %[[C]], 1 : memref<?x?xf32, #[[strided2D]]>
+// CHECK: %[[D_1:.*]] = dim %[[D]], 1 : memref<?x?xf32, #[[strided2D]]>
// CHECK: loop.for %{{.*}} = %{{.*}} to %[[C_0]] step %{{.*}} {
// CHECK: loop.for %{{.*}} = %{{.*}} to %[[D_1]] step %{{.*}} {
// CHECK: loop.for %{{.*}} = %{{.*}} to %[[C_1]] step %{{.*}} {
// CHECK: linalg.matmul
// CHECK: linalg.matmul
-func @f5(%A: !linalg.view<?x?xf32>, %B: !linalg.view<?x?xf32>, %C: !linalg.view<?x?xf32>, %D: !linalg.view<?x?xf32>, %E: !linalg.view<?x?xf32>) -> !linalg.view<?x?xf32> {
+func @f5(%A: memref<?x?xf32, #strided2D>, %B: memref<?x?xf32, #strided2D>, %C: memref<?x?xf32, #strided2D>, %D: memref<?x?xf32, #strided2D>, %E: memref<?x?xf32, #strided2D>) -> memref<?x?xf32, #strided2D> {
%c1 = constant 1 : index
%c0 = constant 0 : index
%c4 = constant 4 : index
%c3 = constant 3 : index
%c2 = constant 2 : index
- %0 = linalg.dim %B, 1 : !linalg.view<?x?xf32>
- %1 = linalg.dim %D, 0 : !linalg.view<?x?xf32>
- %2 = linalg.dim %D, 1 : !linalg.view<?x?xf32>
- linalg.matmul(%A, %B, %C) : !linalg.view<?x?xf32>, !linalg.view<?x?xf32>, !linalg.view<?x?xf32>
- linalg.matmul(%C, %B, %D) : !linalg.view<?x?xf32>, !linalg.view<?x?xf32>, !linalg.view<?x?xf32>
+ %0 = dim %B, 1 : memref<?x?xf32, #strided2D>
+ %1 = dim %D, 0 : memref<?x?xf32, #strided2D>
+ %2 = dim %D, 1 : memref<?x?xf32, #strided2D>
+ linalg.matmul(%A, %B, %C) : memref<?x?xf32, #strided2D>, memref<?x?xf32, #strided2D>, memref<?x?xf32, #strided2D>
+ linalg.matmul(%C, %B, %D) : memref<?x?xf32, #strided2D>, memref<?x?xf32, #strided2D>, memref<?x?xf32, #strided2D>
loop.for %arg5 = %c0 to %1 step %c2 {
loop.for %arg6 = %c0 to %0 step %c3 {
loop.for %arg7 = %c0 to %2 step %c4 {
%3 = affine.apply #map0(%arg5)
%4 = affine.apply #map1(%arg7)
- %5 = linalg.subview %D[%arg5, %3, %c1, %arg7, %4, %c1] : !linalg.view<?x?xf32>
+ %5 = linalg.subview %D[%arg5, %3, %c1, %arg7, %4, %c1] : memref<?x?xf32, #strided2D>
%6 = affine.apply #map2(%arg6)
- %7 = linalg.subview %B[%arg7, %4, %c1, %arg6, %6, %c1] : !linalg.view<?x?xf32>
- %8 = linalg.subview %E[%arg5, %3, %c1, %arg6, %6, %c1] : !linalg.view<?x?xf32>
- linalg.matmul(%5, %7, %8) : !linalg.view<?x?xf32>, !linalg.view<?x?xf32>, !linalg.view<?x?xf32>
+ %7 = linalg.subview %B[%arg7, %4, %c1, %arg6, %6, %c1] : memref<?x?xf32, #strided2D>
+ %8 = linalg.subview %E[%arg5, %3, %c1, %arg6, %6, %c1] : memref<?x?xf32, #strided2D>
+ linalg.matmul(%5, %7, %8) : memref<?x?xf32, #strided2D>, memref<?x?xf32, #strided2D>, memref<?x?xf32, #strided2D>
}
}
}
- return %E : !linalg.view<?x?xf32>
+ return %E : memref<?x?xf32, #strided2D>
}
// CHECK-LABEL: func @f5
// CHECK: (%[[A:.*]]:{{.*}}, %[[B:.*]]:{{.*}}, %[[C:.*]]:{{.*}}, %[[D:.*]]:{{.*}}, %[[E:.*]]:{{.*}})
-// CHECK-DAG: %[[B_1:.*]] = linalg.dim %[[B]], 1 : !linalg.view<?x?xf32>
-// CHECK-DAG: %[[D_0:.*]] = linalg.dim %[[D]], 0 : !linalg.view<?x?xf32>
-// CHECK-DAG: %[[D_1:.*]] = linalg.dim %[[D]], 1 : !linalg.view<?x?xf32>
+// CHECK-DAG: %[[B_1:.*]] = dim %[[B]], 1 : memref<?x?xf32, #[[strided2D]]>
+// CHECK-DAG: %[[D_0:.*]] = dim %[[D]], 0 : memref<?x?xf32, #[[strided2D]]>
+// CHECK-DAG: %[[D_1:.*]] = dim %[[D]], 1 : memref<?x?xf32, #[[strided2D]]>
// Don't fuse C due to false dependence, note that this is too conservative though.
// CHECK: linalg.matmul(%{{.*}}, %{{.*}}, %{{.*}})
// CHECK: loop.for %{{.*}} = %{{.*}} to %[[D_0]] step %{{.*}} {
// CHECK: linalg.matmul
// CHECK: linalg.matmul
-func @f6(%A: !linalg.view<?x?xf32>, %B: !linalg.view<?x?xf32>, %C: !linalg.view<?x?xf32>, %D: !linalg.view<?x?xf32>, %E: !linalg.view<?x?xf32>) -> !linalg.view<?x?xf32> {
+func @f6(%A: memref<?x?xf32, #strided2D>, %B: memref<?x?xf32, #strided2D>, %C: memref<?x?xf32, #strided2D>, %D: memref<?x?xf32, #strided2D>, %E: memref<?x?xf32, #strided2D>) -> memref<?x?xf32, #strided2D> {
%c1 = constant 1 : index
%c0 = constant 0 : index
%c4 = constant 4 : index
%c3 = constant 3 : index
%c2 = constant 2 : index
- %0 = linalg.dim %C, 1 : !linalg.view<?x?xf32>
- linalg.matmul(%A, %B, %C) : !linalg.view<?x?xf32>, !linalg.view<?x?xf32>, !linalg.view<?x?xf32>
- linalg.matmul(%A, %C, %E) : !linalg.view<?x?xf32>, !linalg.view<?x?xf32>, !linalg.view<?x?xf32>
- %1 = linalg.dim %C, 0 : !linalg.view<?x?xf32>
- %2 = linalg.dim %D, 1 : !linalg.view<?x?xf32>
+ %0 = dim %C, 1 : memref<?x?xf32, #strided2D>
+ linalg.matmul(%A, %B, %C) : memref<?x?xf32, #strided2D>, memref<?x?xf32, #strided2D>, memref<?x?xf32, #strided2D>
+ linalg.matmul(%A, %C, %E) : memref<?x?xf32, #strided2D>, memref<?x?xf32, #strided2D>, memref<?x?xf32, #strided2D>
+ %1 = dim %C, 0 : memref<?x?xf32, #strided2D>
+ %2 = dim %D, 1 : memref<?x?xf32, #strided2D>
loop.for %arg5 = %c0 to %1 step %c2 {
loop.for %arg6 = %c0 to %2 step %c3 {
loop.for %arg7 = %c0 to %0 step %c4 {
%3 = affine.apply #map0(%arg5)
%4 = affine.apply #map1(%arg7)
- %5 = linalg.subview %C[%arg5, %3, %c1, %arg7, %4, %c1] : !linalg.view<?x?xf32>
+ %5 = linalg.subview %C[%arg5, %3, %c1, %arg7, %4, %c1] : memref<?x?xf32, #strided2D>
%6 = affine.apply #map2(%arg6)
- %7 = linalg.subview %D[%arg7, %4, %c1, %arg6, %6, %c1] : !linalg.view<?x?xf32>
- %8 = linalg.subview %E[%arg5, %3, %c1, %arg6, %6, %c1] : !linalg.view<?x?xf32>
- linalg.matmul(%5, %7, %8) : !linalg.view<?x?xf32>, !linalg.view<?x?xf32>, !linalg.view<?x?xf32>
+ %7 = linalg.subview %D[%arg7, %4, %c1, %arg6, %6, %c1] : memref<?x?xf32, #strided2D>
+ %8 = linalg.subview %E[%arg5, %3, %c1, %arg6, %6, %c1] : memref<?x?xf32, #strided2D>
+ linalg.matmul(%5, %7, %8) : memref<?x?xf32, #strided2D>, memref<?x?xf32, #strided2D>, memref<?x?xf32, #strided2D>
}
}
}
- return %E : !linalg.view<?x?xf32>
+ return %E : memref<?x?xf32, #strided2D>
}
// CHECK-LABEL: func @f6
// CHECK: (%[[A:.*]]:{{.*}}, %[[B:.*]]:{{.*}}, %[[C:.*]]:{{.*}}, %[[D:.*]]:{{.*}}, %[[E:.*]]:{{.*}})
// CHECK: linalg.matmul
// CHECK-NOT: linalg.matmul
-func @f7(%A: !linalg.view<?x?xf32>, %B: !linalg.view<?x?xf32>, %C: !linalg.view<?x?xf32>, %D: !linalg.view<?x?xf32>, %E: !linalg.view<?x?xf32>) -> !linalg.view<?x?xf32> {
+func @f7(%A: memref<?x?xf32, #strided2D>, %B: memref<?x?xf32, #strided2D>, %C: memref<?x?xf32, #strided2D>, %D: memref<?x?xf32, #strided2D>, %E: memref<?x?xf32, #strided2D>) -> memref<?x?xf32, #strided2D> {
%c1 = constant 1 : index
%c0 = constant 0 : index
%c4 = constant 4 : index
%c3 = constant 3 : index
%c2 = constant 2 : index
- %0 = linalg.dim %A, 0 : !linalg.view<?x?xf32>
- %1 = linalg.dim %A, 1 : !linalg.view<?x?xf32>
- %2 = linalg.dim %C, 1 : !linalg.view<?x?xf32>
- %3 = linalg.dim %C, 0 : !linalg.view<?x?xf32>
- %4 = linalg.dim %D, 1 : !linalg.view<?x?xf32>
- linalg.matmul(%A, %C, %E) : !linalg.view<?x?xf32>, !linalg.view<?x?xf32>, !linalg.view<?x?xf32>
- linalg.matmul(%A, %B, %C) : !linalg.view<?x?xf32>, !linalg.view<?x?xf32>, !linalg.view<?x?xf32>
+ %0 = dim %A, 0 : memref<?x?xf32, #strided2D>
+ %1 = dim %A, 1 : memref<?x?xf32, #strided2D>
+ %2 = dim %C, 1 : memref<?x?xf32, #strided2D>
+ %3 = dim %C, 0 : memref<?x?xf32, #strided2D>
+ %4 = dim %D, 1 : memref<?x?xf32, #strided2D>
+ linalg.matmul(%A, %C, %E) : memref<?x?xf32, #strided2D>, memref<?x?xf32, #strided2D>, memref<?x?xf32, #strided2D>
+ linalg.matmul(%A, %B, %C) : memref<?x?xf32, #strided2D>, memref<?x?xf32, #strided2D>, memref<?x?xf32, #strided2D>
loop.for %arg5 = %c0 to %0 step %c2 {
loop.for %arg6 = %c0 to %2 step %c3 {
loop.for %arg7 = %c0 to %1 step %c4 {
%5 = affine.apply #map0(%arg5)
%6 = affine.apply #map1(%arg7)
- %7 = linalg.subview %A[%arg5, %5, %c1, %arg7, %6, %c1] : !linalg.view<?x?xf32>
+ %7 = linalg.subview %A[%arg5, %5, %c1, %arg7, %6, %c1] : memref<?x?xf32, #strided2D>
%8 = affine.apply #map2(%arg6)
- %9 = linalg.subview %C[%arg7, %6, %c1, %arg6, %8, %c1] : !linalg.view<?x?xf32>
- %10 = linalg.subview %E[%arg5, %5, %c1, %arg6, %8, %c1] : !linalg.view<?x?xf32>
- linalg.matmul(%7, %9, %10) : !linalg.view<?x?xf32>, !linalg.view<?x?xf32>, !linalg.view<?x?xf32>
+ %9 = linalg.subview %C[%arg7, %6, %c1, %arg6, %8, %c1] : memref<?x?xf32, #strided2D>
+ %10 = linalg.subview %E[%arg5, %5, %c1, %arg6, %8, %c1] : memref<?x?xf32, #strided2D>
+ linalg.matmul(%7, %9, %10) : memref<?x?xf32, #strided2D>, memref<?x?xf32, #strided2D>, memref<?x?xf32, #strided2D>
}
}
}
loop.for %arg7 = %c0 to %2 step %c4 {
%5 = affine.apply #map0(%arg5)
%6 = affine.apply #map1(%arg7)
- %7 = linalg.subview %C[%arg5, %5, %c1, %arg7, %6, %c1] : !linalg.view<?x?xf32>
+ %7 = linalg.subview %C[%arg5, %5, %c1, %arg7, %6, %c1] : memref<?x?xf32, #strided2D>
%8 = affine.apply #map2(%arg6)
- %9 = linalg.subview %D[%arg7, %6, %c1, %arg6, %8, %c1] : !linalg.view<?x?xf32>
- %10 = linalg.subview %E[%arg5, %5, %c1, %arg6, %8, %c1] : !linalg.view<?x?xf32>
- linalg.matmul(%7, %9, %10) : !linalg.view<?x?xf32>, !linalg.view<?x?xf32>, !linalg.view<?x?xf32>
+ %9 = linalg.subview %D[%arg7, %6, %c1, %arg6, %8, %c1] : memref<?x?xf32, #strided2D>
+ %10 = linalg.subview %E[%arg5, %5, %c1, %arg6, %8, %c1] : memref<?x?xf32, #strided2D>
+ linalg.matmul(%7, %9, %10) : memref<?x?xf32, #strided2D>, memref<?x?xf32, #strided2D>, memref<?x?xf32, #strided2D>
}
}
}
- return %E : !linalg.view<?x?xf32>
+ return %E : memref<?x?xf32, #strided2D>
}
// CHECK-LABEL: func @f7
// CHECK: (%[[A:.*]]:{{.*}}, %[[B:.*]]:{{.*}}, %[[C:.*]]:{{.*}}, %[[D:.*]]:{{.*}}, %[[E:.*]]:{{.*}})
-// CHECK: %[[A_0:.*]] = linalg.dim %[[A]], 0 : !linalg.view<?x?xf32>
-// CHECK: %[[A_1:.*]] = linalg.dim %[[A]], 1 : !linalg.view<?x?xf32>
-// CHECK: %[[C_1:.*]] = linalg.dim %[[C]], 1 : !linalg.view<?x?xf32>
-// CHECK: %[[C_0:.*]] = linalg.dim %[[C]], 0 : !linalg.view<?x?xf32>
-// CHECK: %[[D_1:.*]] = linalg.dim %[[D]], 1 : !linalg.view<?x?xf32>
+// CHECK: %[[A_0:.*]] = dim %[[A]], 0 : memref<?x?xf32, #[[strided2D]]>
+// CHECK: %[[A_1:.*]] = dim %[[A]], 1 : memref<?x?xf32, #[[strided2D]]>
+// CHECK: %[[C_1:.*]] = dim %[[C]], 1 : memref<?x?xf32, #[[strided2D]]>
+// CHECK: %[[C_0:.*]] = dim %[[C]], 0 : memref<?x?xf32, #[[strided2D]]>
+// CHECK: %[[D_1:.*]] = dim %[[D]], 1 : memref<?x?xf32, #[[strided2D]]>
// CHECK: linalg.matmul(%[[A]], %[[C]], %[[E]])
// CHECK: loop.for %{{.*}} = %{{.*}} to %[[A_0]] step %{{.*}} {
// CHECK: loop.for %{{.*}} = %{{.*}} to %[[C_1]] step %{{.*}} {
// CHECK: linalg.matmul
// CHECK-NOT: linalg.matmul
-func @f8(%A: !linalg.view<?x?xf32>, %B: !linalg.view<?x?xf32>, %C: !linalg.view<?x?xf32>, %D: !linalg.view<?x?xf32>, %E: !linalg.view<?x?xf32>) -> !linalg.view<?x?xf32> {
+func @f8(%A: memref<?x?xf32, #strided2D>, %B: memref<?x?xf32, #strided2D>, %C: memref<?x?xf32, #strided2D>, %D: memref<?x?xf32, #strided2D>, %E: memref<?x?xf32, #strided2D>) -> memref<?x?xf32, #strided2D> {
%c1 = constant 1 : index
%c0 = constant 0 : index
%c4 = constant 4 : index
%c3 = constant 3 : index
%c2 = constant 2 : index
- %0 = linalg.dim %A, 0 : !linalg.view<?x?xf32>
- %1 = linalg.dim %A, 1 : !linalg.view<?x?xf32>
- linalg.matmul(%A, %C, %D) : !linalg.view<?x?xf32>, !linalg.view<?x?xf32>, !linalg.view<?x?xf32>
- linalg.matmul(%A, %B, %C) : !linalg.view<?x?xf32>, !linalg.view<?x?xf32>, !linalg.view<?x?xf32>
- %2 = linalg.dim %D, 1 : !linalg.view<?x?xf32>
+ %0 = dim %A, 0 : memref<?x?xf32, #strided2D>
+ %1 = dim %A, 1 : memref<?x?xf32, #strided2D>
+ linalg.matmul(%A, %C, %D) : memref<?x?xf32, #strided2D>, memref<?x?xf32, #strided2D>, memref<?x?xf32, #strided2D>
+ linalg.matmul(%A, %B, %C) : memref<?x?xf32, #strided2D>, memref<?x?xf32, #strided2D>, memref<?x?xf32, #strided2D>
+ %2 = dim %D, 1 : memref<?x?xf32, #strided2D>
loop.for %arg5 = %c0 to %0 step %c2 {
loop.for %arg6 = %c0 to %2 step %c3 {
loop.for %arg7 = %c0 to %1 step %c4 {
%3 = affine.apply #map0(%arg5)
%4 = affine.apply #map1(%arg7)
- %5 = linalg.subview %A[%arg5, %3, %c1, %arg7, %4, %c1] : !linalg.view<?x?xf32>
+ %5 = linalg.subview %A[%arg5, %3, %c1, %arg7, %4, %c1] : memref<?x?xf32, #strided2D>
%6 = affine.apply #map2(%arg6)
- %7 = linalg.subview %D[%arg7, %4, %c1, %arg6, %6, %c1] : !linalg.view<?x?xf32>
- %8 = linalg.subview %E[%arg5, %3, %c1, %arg6, %6, %c1] : !linalg.view<?x?xf32>
- linalg.matmul(%5, %7, %8) : !linalg.view<?x?xf32>, !linalg.view<?x?xf32>, !linalg.view<?x?xf32>
+ %7 = linalg.subview %D[%arg7, %4, %c1, %arg6, %6, %c1] : memref<?x?xf32, #strided2D>
+ %8 = linalg.subview %E[%arg5, %3, %c1, %arg6, %6, %c1] : memref<?x?xf32, #strided2D>
+ linalg.matmul(%5, %7, %8) : memref<?x?xf32, #strided2D>, memref<?x?xf32, #strided2D>, memref<?x?xf32, #strided2D>
}
}
}
- return %E : !linalg.view<?x?xf32>
+ return %E : memref<?x?xf32, #strided2D>
}
// CHECK-LABEL: func @f8
// CHECK: (%[[A:.*]]:{{.*}}, %[[B:.*]]:{{.*}}, %[[C:.*]]:{{.*}}, %[[D:.*]]:{{.*}}, %[[E:.*]]:{{.*}})
n_loop_types = [2, 0, 0],
n_views = [2, 1]
}
-func @pointwise(%A: !linalg.view<?x?xf32>, %B: !linalg.view<?x?xf32>, %C: !linalg.view<?x?xf32>, %D: !linalg.view<?x?xf32>) {
+func @pointwise(%A: memref<?x?xf32, #strided2D>, %B: memref<?x?xf32, #strided2D>, %C: memref<?x?xf32, #strided2D>, %D: memref<?x?xf32, #strided2D>) {
%c1 = constant 1 : index
%c0 = constant 0 : index
%c3 = constant 3 : index
^bb0(%E: f32, %arg5: f32, %arg6: f32): // no predecessors
%2 = addf %E, %arg5 : f32
linalg.yield %2 : f32
- }: !linalg.view<?x?xf32>, !linalg.view<?x?xf32>, !linalg.view<?x?xf32>
- %0 = linalg.dim %B, 0 : !linalg.view<?x?xf32>
- %1 = linalg.dim %B, 1 : !linalg.view<?x?xf32>
+ }: memref<?x?xf32, #strided2D>, memref<?x?xf32, #strided2D>, memref<?x?xf32, #strided2D>
+ %0 = dim %B, 0 : memref<?x?xf32, #strided2D>
+ %1 = dim %B, 1 : memref<?x?xf32, #strided2D>
loop.for %E = %c0 to %0 step %c2 {
loop.for %arg5 = %c0 to %1 step %c3 {
%2 = affine.apply #map0(%E)
%3 = affine.apply #map1(%arg5)
- %4 = linalg.subview %B[%E, %2, %c1, %arg5, %3, %c1] : !linalg.view<?x?xf32>
- %5 = linalg.subview %C[%E, %2, %c1, %arg5, %3, %c1] : !linalg.view<?x?xf32>
- %6 = linalg.subview %D[%E, %2, %c1, %arg5, %3, %c1] : !linalg.view<?x?xf32>
+ %4 = linalg.subview %B[%E, %2, %c1, %arg5, %3, %c1] : memref<?x?xf32, #strided2D>
+ %5 = linalg.subview %C[%E, %2, %c1, %arg5, %3, %c1] : memref<?x?xf32, #strided2D>
+ %6 = linalg.subview %D[%E, %2, %c1, %arg5, %3, %c1] : memref<?x?xf32, #strided2D>
linalg.generic #pointwise_2d_trait %4, %5, %6 {
^bb0(%arg6: f32, %arg7: f32, %arg8: f32): // no predecessors
%7 = mulf %arg6, %arg7 : f32
linalg.yield %7 : f32
- }: !linalg.view<?x?xf32>, !linalg.view<?x?xf32>, !linalg.view<?x?xf32>
+ }: memref<?x?xf32, #strided2D>, memref<?x?xf32, #strided2D>, memref<?x?xf32, #strided2D>
}
}
return
// -----
-func @load_number_of_indices(%v : !linalg.view<f32>) {
- // expected-error @+2 {{expected 0 indices, got 1}}
+func @load_number_of_indices(%v : memref<f32>) {
+ // expected-error @+2 {{incorrect number of indices for load}}
%c0 = constant 0 : index
- linalg.load %v[%c0] : !linalg.view<f32>
+ load %v[%c0] : memref<f32>
}
// -----
-func @slice_number_of_indexings(%arg0: !linalg.view<?x?xf32>) {
+func @slice_number_of_indexings(%arg0: memref<?x?xf32, (i, j)[off, M]->(off + M * i + j)>) {
// expected-error @+2 {{expected 2 indexings, got 1}}
%c0 = constant 0: index
- %0 = linalg.slice %arg0[%c0] : !linalg.view<?x?xf32>, index, !linalg.view<?x?xf32>
+ %0 = linalg.slice %arg0[%c0] : memref<?x?xf32, (i, j)[off, M]->(off + M * i + j)>, index, memref<?x?xf32, (i, j)[off, M]->(off + M * i + j)>
}
// -----
-func @slice_rank_vs_range_indices(%arg0: !linalg.view<?x?xf32>) {
+func @slice_rank_vs_range_indices(%arg0: memref<?x?xf32, (i, j)[off, M]->(off + M * i + j)>) {
// expected-error @+2 {{op expected rank of the view(1) to be the number of ranges(0)}}
%c0 = constant 0: index
- %0 = linalg.slice %arg0[%c0, %c0] : !linalg.view<?x?xf32>, index, index, !linalg.view<?xf32>
+ %0 = linalg.slice %arg0[%c0, %c0] : memref<?x?xf32, (i, j)[off, M]->(off + M * i + j)>, index, index, memref<?xf32, (i)[off]->(off + i)>
}
// -----
-func @store_number_of_indices(%v : !linalg.view<f32>) {
- // expected-error @+3 {{expected 0 indices, got 1}}
+func @store_number_of_indices(%v : memref<f32>) {
+ // expected-error @+3 {{store index operand count not equal to memref rank}}
%c0 = constant 0 : index
%f0 = constant 0.0 : f32
- linalg.store %f0, %v[%c0] : !linalg.view<f32>
+ store %f0, %v[%c0] : memref<f32>
}
// -----
-func @subview_number_of_indices(%v : !linalg.view<?x?xf32>) {
- // expected-error @+2 {{expected a view followed by 6 indices specifying a range for each dimension}}
+func @subview_number_of_indices(%v : memref<?x?xf32, (i, j)[off, M]->(off + M * i + j)>) {
+ // expected-error @+2 {{expected a strided memref followed by 6 indices specifying a range for each dimension}}
%c0 = constant 0 : index
- linalg.subview %v[%c0, %c0] : !linalg.view<?x?xf32>
+ linalg.subview %v[%c0, %c0] : memref<?x?xf32, (i, j)[off, M]->(off + M * i + j)>
}
// -----
-func @transpose_not_permutation(%v : !linalg.view<?x?xf32>) {
+func @transpose_not_permutation(%v : memref<?x?xf32, (i, j)[off, M]->(off + M * i + j)>) {
// expected-error @+1 {{expected a permutation map}}
- linalg.transpose %v (i, j) -> (i, i) : !linalg.view<?x?xf32>
+ linalg.transpose %v (i, j) -> (i, i) : memref<?x?xf32, (i, j)[off, M]->(off + M * i + j)>
}
// -----
-func @transpose_bad_rank(%v : !linalg.view<?x?xf32>) {
+func @transpose_bad_rank(%v : memref<?x?xf32, (i, j)[off, M]->(off + M * i + j)>) {
// expected-error @+1 {{expected a permutation map of same rank as the view}}
- linalg.transpose %v (i) -> (i) : !linalg.view<?x?xf32>
+ linalg.transpose %v (i) -> (i) : memref<?x?xf32, (i, j)[off, M]->(off + M * i + j)>
}
// -----
func @view_type(%buf: !linalg.buffer<?xf32>, %min: index, %max: index, %step: index) {
- // expected-error @+2 {{expected view type}}
+ // expected-error @+2 {{expected memref type}}
%r = linalg.range %min:%max:%step : !linalg.range
%0 = linalg.view %buf[%r]: !linalg.buffer<?xf32> -> index
}
func @view_num_ranges(%buf: !linalg.buffer<?xf32>, %min: index, %max: index, %step: index) {
// expected-error @+2 {{expected 2 ranges}}
%r = linalg.range %min:%max:%step : !linalg.range
- %0 = linalg.view %buf[%r]: !linalg.buffer<?xf32> -> !linalg.view<?x?xf32>
+ %0 = linalg.view %buf[%r]: !linalg.buffer<?xf32> -> memref<?x?xf32, (i, j)[off, M]->(off + M * i + j)>
}
// -----
-func @yield_parent(%arg0: !linalg.view<?xf32>) {
+func @yield_parent(%arg0: memref<?xf32, (i)[off]->(off + i)>) {
// expected-error @+1 {{op expected 'linalg.generic' parent op}}
- linalg.yield %arg0: !linalg.view<?xf32>
+ linalg.yield %arg0: memref<?xf32, (i)[off]->(off + i)>
}
// -----
-func @generic_at_least_2_operands(%arg0: !linalg.view<f32>) {
+func @generic_at_least_2_operands(%arg0: memref<f32>) {
// expected-error @+1 {{op expected 2 or more operands}}
linalg.generic {
fun = @foo,
indexing_maps = [ () -> (0) ],
n_views = [1, 1],
n_loop_types = [0, 0, 0]
- } %arg0: !linalg.view<f32>
+ } %arg0: memref<f32>
}
// -----
-func @generic_exactly_2_views(%arg0: !linalg.view<f32>) {
+func @generic_exactly_2_views(%arg0: memref<f32>) {
// expected-error @+1 {{op expected exactly 2 view operands}}
linalg.generic {
fun = @foo,
indexing_maps = [ () -> (0) ],
n_views = [1, 1],
n_loop_types = [0, 0, 0]
- } %arg0, %arg0, %arg0: !linalg.view<f32>, !linalg.view<f32>, !linalg.view<f32>
+ } %arg0, %arg0, %arg0: memref<f32>, memref<f32>, memref<f32>
}
// -----
-func @generic_undefined_fun(%arg0: !linalg.view<f32>) {
+func @generic_undefined_fun(%arg0: memref<f32>) {
// expected-error @+1 {{op expected fun attribute to refer to a defined symbol}}
linalg.generic {
fun = @foo,
indexing_maps = [ () -> (0) ],
n_views = [1, 1],
n_loop_types = [0, 0, 0]
- } %arg0, %arg0: !linalg.view<f32>, !linalg.view<f32>
+ } %arg0, %arg0: memref<f32>, memref<f32>
}
// -----
func @foo() { return }
-func @generic_mismatched_num_arguments(%arg0: !linalg.view<f32>) {
+func @generic_mismatched_num_arguments(%arg0: memref<f32>) {
// expected-error @+1 {{op expected fun arguments to match number of views}}
linalg.generic {
fun = @foo,
indexing_maps = [ () -> (0) ],
n_views = [0, 1],
n_loop_types = [0, 0, 0]
- } %arg0: !linalg.view<f32>
+ } %arg0: memref<f32>
}
// -----
func @foo(%0: i32) { return }
-func @generic_mismatched_num_returns(%arg0: !linalg.view<f32>) {
+func @generic_mismatched_num_returns(%arg0: memref<f32>) {
// expected-error @+1 {{op expected fun results to match number of output views}}
linalg.generic {
fun = @foo,
indexing_maps = [ () -> (0) ],
n_views = [0, 1],
n_loop_types = [0, 0, 0]
- } %arg0: !linalg.view<f32>
+ } %arg0: memref<f32>
}
// -----
func @foo(%0: i32) -> i32 { return %0: i32 }
-func @generic_symbol_in_map(%arg0: !linalg.view<f32>) {
+func @generic_symbol_in_map(%arg0: memref<f32>) {
// expected-error @+1 {{op expected indexing_map #0 to have no symbols}}
linalg.generic {
fun = @foo,
indexing_maps = [ ()[N] -> (0) ],
n_views = [0, 1],
n_loop_types = [1, 0, 0]
- } %arg0: !linalg.view<f32>
+ } %arg0: memref<f32>
}
// -----
func @foo(%0: i32) -> i32 { return %0: i32 }
-func @generic_wrong_dim_in_map(%arg0: !linalg.view<f32>) {
+func @generic_wrong_dim_in_map(%arg0: memref<f32>) {
// expected-error @+1 {{op expected indexing_map #0 to have 1 dim(s) to match the number of loops}}
linalg.generic {
fun = @foo,
indexing_maps = [ () -> (0) ],
n_views = [0, 1],
n_loop_types = [1, 0, 0]
- } %arg0: !linalg.view<f32>
+ } %arg0: memref<f32>
}
// -----
func @foo(%0: i32) -> i32 { return %0: i32 }
-func @generic_zero_d_view(%arg0: !linalg.view<f32>) {
- // expected-error @+1 {{op expected indexing_map #0 to be 0 to match 0-D view: '!linalg.view<f32>'}}
+func @generic_zero_d_view(%arg0: memref<f32>) {
+ // expected-error @+1 {{op expected indexing_map #0 to be 0 to match 0-D view: 'memref<f32>'}}
linalg.generic {
fun = @foo,
indexing_maps = [ () -> (1) ],
n_views = [0, 1],
n_loop_types = [0, 0, 0]
- } %arg0: !linalg.view<f32>
+ } %arg0: memref<f32>
}
// -----
func @foo(%0: f32) -> f32 { return %0: f32 }
-func @generic_one_d_view(%arg0: !linalg.view<?xf32>) {
- // expected-error @+1 {{op expected indexing_map #0 results to match view rank: '!linalg.view<?xf32>'}}
+func @generic_one_d_view(%arg0: memref<?xf32, (i)[off]->(off + i)>) {
+ // expected-error @+1 {{op expected indexing_map #0 results to match view rank: 'memref<?xf32, (d0)[s0] -> (d0 + s0)>'}}
linalg.generic {
fun = @foo,
indexing_maps = [ () -> (0, 0) ],
n_views = [0, 1],
n_loop_types = [0, 0, 0]
- } %arg0: !linalg.view<?xf32>
+ } %arg0: memref<?xf32, (i)[off]->(off + i)>
}
// -----
return %1: f32
}
-func @generic_fun_arg_0_element_type(%arg0: !linalg.view<?xf32>) {
+func @generic_fun_arg_0_element_type(%arg0: memref<?xf32, (i)[off]->(off + i)>) {
// expected-error @+1 {{op expected fun argument 0 to match view element type: 'f32'}}
linalg.generic {
fun = @foo,
indexing_maps = [ () -> (0) ],
n_views = [0, 1],
n_loop_types = [0, 0, 0]
- } %arg0: !linalg.view<?xf32>
+ } %arg0: memref<?xf32, (i)[off]->(off + i)>
}
// -----
return %1: i4
}
-func @generic_fun_result_0_element_type(%arg0: !linalg.view<?xf32>) {
+func @generic_fun_result_0_element_type(%arg0: memref<?xf32, (i)[off]->(off + i)>) {
// expected-error @+1 {{op expected fun result 0 to match output view element type: 'f32'}}
linalg.generic {
fun = @foo,
indexing_maps = [ () -> (0) ],
n_views = [0, 1],
n_loop_types = [0, 0, 0]
- } %arg0: !linalg.view<?xf32>
+ } %arg0: memref<?xf32, (i)[off]->(off + i)>
}
// -----
func @foo(%0: f32, %1: f32) -> f32 { return %1: f32 }
-func @generic_singular_maps(%arg0: !linalg.view<?xf32>, %arg1: !linalg.view<?xf32>) {
+func @generic_singular_maps(%arg0: memref<?xf32, (i)[off]->(off + i)>, %arg1: memref<?xf32, (i)[off]->(off + i)>) {
// expected-error @+1 {{op expected the concatenation of maps in indexing_map to be invertible}}
linalg.generic {
fun = @foo,
],
n_views = [1, 1],
n_loop_types = [2, 0, 0]
- } %arg0, %arg1: !linalg.view<?xf32>, !linalg.view<?xf32>
+ } %arg0, %arg1: memref<?xf32, (i)[off]->(off + i)>, memref<?xf32, (i)[off]->(off + i)>
}
////////////////////////////////////////////////////////////////////////////////
// -----
-func @generic_empty_region(%arg0: !linalg.view<f32>) {
+func @generic_empty_region(%arg0: memref<f32>) {
// expected-error @+1 {{op expected region with 1 block}}
linalg.generic {
indexing_maps = [ () -> (0) ],
} %arg0, %arg0 {
^bb1:
^bb2:
- }: !linalg.view<f32>, !linalg.view<f32>
+ }: memref<f32>, memref<f32>
}
// -----
-func @generic_mismatched_num_arguments(%arg0: !linalg.view<f32>) {
+func @generic_mismatched_num_arguments(%arg0: memref<f32>) {
// expected-error @+1 {{op expected number of block arguments to match number of views}}
linalg.generic {
indexing_maps = [ () -> (0) ],
n_loop_types = [0, 0, 0]
} %arg0 {
^bb:
- }: !linalg.view<f32>
+ }: memref<f32>
}
// -----
-func @generic_block_arg_type(%arg0: !linalg.view<f32>) {
- // expected-error @+1 {{op expected block argument 0 of the same type as elemental type of output view: '!linalg.view<f32>'}}
+func @generic_block_arg_type(%arg0: memref<f32>) {
+ // expected-error @+1 {{op expected block argument 0 of the same type as elemental type of output view: 'memref<f32>'}}
linalg.generic {
indexing_maps = [ () -> (0) ],
n_views = [0, 1],
n_loop_types = [0, 0, 0]
} %arg0 {
^bb(%i: i1):
- }: !linalg.view<f32>
+ }: memref<f32>
}
// -----
-func @generic_fun_result_0_element_type(%arg0: !linalg.view<?xf32>) {
+func @generic_fun_result_0_element_type(%arg0: memref<?xf32, (i)[off]->(off + i)>) {
// expected-error @+8 {{type of return operand 0 ('i1') doesn't match view element type ('f32')}}
linalg.generic {
indexing_maps = [ (i) -> (i) ],
^bb(%i: f32):
%0 = constant 0: i1
linalg.yield %0: i1
- }: !linalg.view<?xf32>
+ }: memref<?xf32, (i)[off]->(off + i)>
}
-// RUN: mlir-opt %s -linalg-lower-to-llvm-dialect | FileCheck %s
+// RUN: mlir-opt %s -linalg-convert-to-llvm
+// RUN: mlir-opt %s -linalg-convert-to-llvm | FileCheck %s
+
+#strided1D = (d0)[s0] -> (d0 + s0)
+#strided2D = (d0, d1)[s0, s1] -> (d0 * s1 + s0 + d1)
+#strided3D = (d0, d1, d2)[s0, s1, s2] -> (d0 * s1 + s0 + d1 * s2 + d2)
func @buffer_size(%arg0: !linalg.buffer<?xf32>) {
%c1 = constant 1 : index
// CHECK-NEXT: llvm.insertvalue %{{.*}}, %{{.*}}[2] : !llvm<"{ i64, i64, i64 }">
func @view(%arg0: !linalg.buffer<?xf32>, %arg1: !linalg.range) {
- %0 = linalg.view %arg0[%arg1] : !linalg.buffer<?xf32> -> !linalg.view<?xf32>
+ %0 = linalg.view %arg0[%arg1] : !linalg.buffer<?xf32> -> memref<?xf32, #strided1D>
return
}
// CHECK-LABEL: func @view
// CHECK-NEXT: llvm.return
func @view3d(%arg0: !linalg.buffer<?xf32>, %arg1: !linalg.range, %arg2: !linalg.range, %arg3: !linalg.range) {
- %0 = linalg.view %arg0[%arg1, %arg2, %arg3] : !linalg.buffer<?xf32> -> !linalg.view<?x?x?xf32>
+ %0 = linalg.view %arg0[%arg1, %arg2, %arg3] : !linalg.buffer<?xf32> -> memref<?x?x?xf32, #strided3D>
return
}
// CHECK-LABEL: func @view3d
// CHECK-NEXT: llvm.insertvalue %{{.*}}, %{{.*}}[3, 1] : !llvm<"{ float*, i64, [3 x i64], [3 x i64] }">
func @slice(%arg0: !linalg.buffer<?xf32>, %arg1: !linalg.range) {
- %0 = linalg.view %arg0[%arg1] : !linalg.buffer<?xf32> -> !linalg.view<?xf32>
- %1 = linalg.slice %0[%arg1] : !linalg.view<?xf32>, !linalg.range, !linalg.view<?xf32>
+ %0 = linalg.view %arg0[%arg1] : !linalg.buffer<?xf32> -> memref<?xf32, #strided1D>
+ %1 = linalg.slice %0[%arg1] : memref<?xf32, #strided1D>, !linalg.range, memref<?xf32, #strided1D>
return
}
// CHECK-LABEL: func @slice
// insert ptr for view op
// CHECK: llvm.insertvalue %{{.*}}, %{{.*}}[0] : !llvm<"{ float*, i64, [1 x i64], [1 x i64] }">
// insert data ptr for slice op
-// CHECK: llvm.insertvalue %{{.*}}, %{{.*}}[0] : !llvm<"{ float*, i64, [1 x i64], [1 x i64] }">
-// CHECK-NEXT: llvm.extractvalue %{{.*}}[3, 0] : !llvm<"{ float*, i64, [1 x i64], [1 x i64] }">
+// CHECK: llvm.extractvalue %{{.*}}[3, 0] : !llvm<"{ float*, i64, [1 x i64], [1 x i64] }">
// CHECK-NEXT: llvm.extractvalue %{{.*}}[1] : !llvm<"{ float*, i64, [1 x i64], [1 x i64] }">
// CHECK-NEXT: llvm.extractvalue %{{.*}}[0] : !llvm<"{ i64, i64, i64 }">
// CHECK-NEXT: llvm.mul %{{.*}}, %{{.*}} : !llvm.i64
// CHECK-NEXT: llvm.add %{{.*}}, %{{.*}} : !llvm.i64
// insert offset
+// CHECK: llvm.insertvalue %{{.*}}, %{{.*}}[0] : !llvm<"{ float*, i64, [1 x i64], [1 x i64] }">
// CHECK-NEXT: llvm.insertvalue %{{.*}}, %{{.*}}[1] : !llvm<"{ float*, i64, [1 x i64], [1 x i64] }">
+// CHECK-NEXT: llvm.mlir.constant(0 : index)
// CHECK-NEXT: llvm.extractvalue %{{.*}}[0] : !llvm<"{ i64, i64, i64 }">
// CHECK-NEXT: llvm.extractvalue %{{.*}}[1] : !llvm<"{ i64, i64, i64 }">
// CHECK-NEXT: llvm.extractvalue %{{.*}}[2] : !llvm<"{ i64, i64, i64 }">
// CHECK-NEXT: llvm.insertvalue %{{.*}}, %{{.*}}[2, 0] : !llvm<"{ float*, i64, [1 x i64], [1 x i64] }">
// CHECK-NEXT: llvm.insertvalue %{{.*}}, %{{.*}}[3, 0] : !llvm<"{ float*, i64, [1 x i64], [1 x i64] }">
-func @dot(%arg0: !linalg.view<?xf32>, %arg1: !linalg.view<?xf32>, %arg2: !linalg.view<f32>) {
- linalg.dot(%arg0, %arg1, %arg2) : !linalg.view<?xf32>, !linalg.view<?xf32>, !linalg.view<f32>
+func @dot(%arg0: memref<?xf32, #strided1D>, %arg1: memref<?xf32, #strided1D>, %arg2: memref<f32>) {
+ linalg.dot(%arg0, %arg1, %arg2) : memref<?xf32, #strided1D>, memref<?xf32, #strided1D>, memref<f32>
return
}
-// CHECK-LABEL: func @dot(%{{.*}}: !llvm<"{ float*, i64, [1 x i64], [1 x i64] }">, %{{.*}}: !llvm<"{ float*, i64, [1 x i64], [1 x i64] }">, %{{.*}}: !llvm<"{ float*, i64, [0 x i64], [0 x i64] }">) {
+// CHECK-LABEL: func @dot(%{{.*}}: !llvm<"{ float*, i64, [1 x i64], [1 x i64] }*">, %{{.*}}: !llvm<"{ float*, i64, [1 x i64], [1 x i64] }*">, %{{.*}}: !llvm<"{ float*, i64 }*">) {
// CHECK-COUNT-3: llvm.mlir.constant(1 : index){{.*[[:space:]].*}}llvm.alloca{{.*[[:space:]].*}}llvm.store
-// CHECK-NEXT: llvm.call @linalg_dot_viewxf32_viewxf32_viewf32(%{{.*}}, %{{.*}}, %{{.*}}) : (!llvm<"{ float*, i64, [1 x i64], [1 x i64] }*">, !llvm<"{ float*, i64, [1 x i64], [1 x i64] }*">, !llvm<"{ float*, i64, [0 x i64], [0 x i64] }*">) -> ()
+// CHECK-NEXT: llvm.call @linalg_dot_viewsxf32_viewsxf32_viewf32(%{{.*}}, %{{.*}}, %{{.*}}) : (!llvm<"{ float*, i64, [1 x i64], [1 x i64] }*">, !llvm<"{ float*, i64, [1 x i64], [1 x i64] }*">, !llvm<"{ float*, i64 }*">) -> ()
-func @dim(%arg0: !linalg.view<?x?xf32>) {
- %0 = linalg.dim %arg0, 1 : !linalg.view<?x?xf32>
+func @dim(%arg0: memref<?x?xf32, #strided2D>) {
+ %0 = dim %arg0, 1 : memref<?x?xf32, #strided2D>
return
}
-// CHECK-LABEL: func @dim(%{{.*}}: !llvm<"{ float*, i64, [2 x i64], [2 x i64] }">) {
+// CHECK-LABEL: func @dim(%{{.*}}: !llvm<"{ float*, i64, [2 x i64], [2 x i64] }*">) {
// CHECK: llvm.extractvalue %{{.*}}[2, 1] : !llvm<"{ float*, i64, [2 x i64], [2 x i64] }">
-func @subview(%arg0: !linalg.view<?x?xf32>) {
+func @subview(%arg0: memref<?x?xf32, #strided2D>) {
%c0 = constant 0 : index
- %0 = linalg.subview %arg0[%c0, %c0, %c0, %c0, %c0, %c0] : !linalg.view<?x?xf32>
+ %0 = linalg.subview %arg0[%c0, %c0, %c0, %c0, %c0, %c0] : memref<?x?xf32, #strided2D>
return
}
// CHECK-LABEL: func @subview
// CHECK-NEXT: llvm.select %{{.*}}, %{{.*}}, %{{.*}} : !llvm.i1, !llvm.i64
// CHECK-NEXT: llvm.mul %{{.*}}, %{{.*}} : !llvm.i64
-func @view_with_range_and_index(%arg0: !linalg.view<?x?xf64>) {
+func @view_with_range_and_index(%arg0: memref<?x?xf64, #strided2D>) {
%c0 = constant 0 : index
%c1 = constant 1 : index
%R = linalg.range %c0:%c1:%c1 : !linalg.range
loop.for %i0 = %c0 to %c1 step %c1 {
- %1 = linalg.slice %arg0[%i0, %R] : !linalg.view<?x?xf64>, index, !linalg.range, !linalg.view<?xf64>
+ %1 = linalg.slice %arg0[%i0, %R] : memref<?x?xf64, #strided2D>, index, !linalg.range, memref<?xf64, #strided1D>
}
return
}
// CHECK-LABEL: func @view_with_range_and_index
// loop-body.
// CHECK: llvm.mlir.undef : !llvm<"{ double*, i64, [1 x i64], [1 x i64] }">
-// CHECK: llvm.insertvalue %{{.*}}, %{{.*}}[0] : !llvm<"{ double*, i64, [1 x i64], [1 x i64] }">
// CHECK: llvm.extractvalue %{{.*}}[3, 0] : !llvm<"{ double*, i64, [2 x i64], [2 x i64] }">
// CHECK: llvm.extractvalue %{{.*}}[3, 1] : !llvm<"{ double*, i64, [2 x i64], [2 x i64] }">
// CHECK: llvm.extractvalue %{{.*}}[1] : !llvm<"{ double*, i64, [2 x i64], [2 x i64] }">
+// CHECK: llvm.insertvalue %{{.*}}, %{{.*}}[0] : !llvm<"{ double*, i64, [1 x i64], [1 x i64] }">
// CHECK: llvm.insertvalue %{{.*}}[1] : !llvm<"{ double*, i64, [1 x i64], [1 x i64] }">
// CHECK: llvm.extractvalue %{{.*}}[0] : !llvm<"{ i64, i64, i64 }">
// CHECK: llvm.extractvalue %{{.*}}[1] : !llvm<"{ i64, i64, i64 }">
// CHECK: llvm.insertvalue %{{.*}}[2, 0] : !llvm<"{ double*, i64, [1 x i64], [1 x i64] }">
// CHECK: llvm.insertvalue %{{.*}}[3, 0] : !llvm<"{ double*, i64, [1 x i64], [1 x i64] }">
-func @copy(%arg0: !linalg.view<?x?x?xf32>, %arg1: !linalg.view<?x?x?xf32>) {
- linalg.copy(%arg0, %arg1) : !linalg.view<?x?x?xf32>, !linalg.view<?x?x?xf32>
+func @copy(%arg0: memref<?x?x?xf32, #strided3D>, %arg1: memref<?x?x?xf32, #strided3D>) {
+ linalg.copy(%arg0, %arg1) : memref<?x?x?xf32, #strided3D>, memref<?x?x?xf32, #strided3D>
return
}
// CHECK-LABEL: func @copy
-// CHECK: llvm.call @linalg_copy_viewxxxf32_viewxxxf32(%{{.*}}, %{{.*}}) : (!llvm<"{ float*, i64, [3 x i64], [3 x i64] }*">, !llvm<"{ float*, i64, [3 x i64], [3 x i64] }*">) -> ()
+// CHECK: llvm.call @linalg_copy_viewsxsxsxf32_viewsxsxsxf32(%{{.*}}, %{{.*}}) : (!llvm<"{ float*, i64, [3 x i64], [3 x i64] }*">, !llvm<"{ float*, i64, [3 x i64], [3 x i64] }*">) -> ()
-func @transpose(%arg0: !linalg.view<?x?x?xf32>) {
- %0 = linalg.transpose %arg0 (i, j, k) -> (k, i, j) : !linalg.view<?x?x?xf32>
+func @transpose(%arg0: memref<?x?x?xf32, #strided3D>) {
+ %0 = linalg.transpose %arg0 (i, j, k) -> (k, i, j) : memref<?x?x?xf32, #strided3D>
return
}
// CHECK-LABEL: func @transpose
// CHECK: llvm.extractvalue {{.*}}[2, 2] : !llvm<"{ float*, i64, [3 x i64], [3 x i64] }">
// CHECK: llvm.insertvalue {{.*}}[2, 1] : !llvm<"{ float*, i64, [3 x i64], [3 x i64] }">
-func @copy_transpose(%arg0: !linalg.view<?x?x?xf32>, %arg1: !linalg.view<?x?x?xf32>) {
+func @copy_transpose(%arg0: memref<?x?x?xf32, #strided3D>, %arg1: memref<?x?x?xf32, #strided3D>) {
linalg.copy(%arg0, %arg1) {inputPermutation = (i, j, k) -> (i, k, j),
outputPermutation = (i, j, k) -> (k, j, i)}
- : !linalg.view<?x?x?xf32>, !linalg.view<?x?x?xf32>
+ : memref<?x?x?xf32, #strided3D>, memref<?x?x?xf32, #strided3D>
return
}
// CHECK-LABEL: func @copy
// CHECK: llvm.insertvalue {{.*}}[2, 0] : !llvm<"{ float*, i64, [3 x i64], [3 x i64] }">
// Call external copy after promoting input and output structs to pointers
// CHECK-COUNT-2: llvm.mlir.constant(1 : index){{.*[[:space:]].*}}llvm.alloca{{.*[[:space:]].*}}llvm.store
-// CHECK: llvm.call @linalg_copy_viewxxxf32_viewxxxf32(%{{.*}}, %{{.*}}) : (!llvm<"{ float*, i64, [3 x i64], [3 x i64] }*">, !llvm<"{ float*, i64, [3 x i64], [3 x i64] }*">) -> ()
+// CHECK: llvm.call @linalg_copy_viewsxsxsxf32_viewsxsxsxf32(%{{.*}}, %{{.*}}) : (!llvm<"{ float*, i64, [3 x i64], [3 x i64] }*">, !llvm<"{ float*, i64, [3 x i64], [3 x i64] }*">) -> ()
// RUN: mlir-opt %s -linalg-lower-to-loops | FileCheck %s
-// CHECK-DAG: #[[S2D1:.*]] = (d0, d1) -> (d0 * 2 + d1)
-// CHECK-DAG: #[[S2D3:.*]] = (d0, d1) -> (d0 * 2 + d1 * 4)
-// CHECK-DAG: #[[S3D2:.*]] = (d0, d1) -> (d0 * 3 + d1 * 5)
+// CHECK-DAG: #[[strided1D:.*]] = (d0)[s0] -> (d0 + s0)
+#strided1D = (d0)[s0] -> (d0 + s0)
+// CHECK-DAG: #[[strided2D:.*]] = (d0, d1)[s0, s1] -> (d0 * s1 + s0 + d1)
+#strided2D = (d0, d1)[s0, s1] -> (d0 * s1 + s0 + d1)
+// CHECK-DAG: #[[strided3D:.*]] = (d0, d1, d2)[s0, s1, s2] -> (d0 * s1 + s0 + d1 * s2 + d2)
+#strided3D = (d0, d1, d2)[s0, s1, s2] -> (d0 * s1 + s0 + d1 * s2 + d2)
+// CHECK-DAG: #[[strided4D:.*]] = (d0, d1, d2, d3)[s0, s1, s2, s3] -> (d0 * s1 + s0 + d1 * s2 + d2 * s3 + d3)
+#strided4D = (d0, d1, d2, d3)[s0, s1, s2, s3] -> (d0 * s1 + s0 + d1 * s2 + d2 * s3 + d3)
+
+// CHECK-DAG: #[[Stride2Dilation1:.*]] = (d0, d1) -> (d0 * 2 + d1)
+// CHECK-DAG: #[[Stride2Dilation4:.*]] = (d0, d1) -> (d0 * 2 + d1 * 4)
+// CHECK-DAG: #[[Stride3Dilation5:.*]] = (d0, d1) -> (d0 * 3 + d1 * 5)
+
func @matmul(%arg0: !linalg.buffer<?xf32>, %arg1: index, %arg2: index, %arg3: index) {
%c0 = constant 0 : index
%I = linalg.range %c0:%arg1:%c1 : !linalg.range
%J = linalg.range %c0:%arg2:%c1 : !linalg.range
%K = linalg.range %c0:%arg3:%c1 : !linalg.range
- %A = linalg.view %arg0[%I, %K] : !linalg.buffer<?xf32> -> !linalg.view<?x?xf32>
- %B = linalg.view %arg0[%K, %J] : !linalg.buffer<?xf32> -> !linalg.view<?x?xf32>
- %C = linalg.view %arg0[%I, %J] : !linalg.buffer<?xf32> -> !linalg.view<?x?xf32>
- linalg.matmul(%A, %B, %C) : !linalg.view<?x?xf32>, !linalg.view<?x?xf32>, !linalg.view<?x?xf32>
+ %A = linalg.view %arg0[%I, %K] : !linalg.buffer<?xf32> -> memref<?x?xf32, #strided2D>
+ %B = linalg.view %arg0[%K, %J] : !linalg.buffer<?xf32> -> memref<?x?xf32, #strided2D>
+ %C = linalg.view %arg0[%I, %J] : !linalg.buffer<?xf32> -> memref<?x?xf32, #strided2D>
+ linalg.matmul(%A, %B, %C) : memref<?x?xf32, #strided2D>, memref<?x?xf32, #strided2D>, memref<?x?xf32, #strided2D>
return
}
// CHECK-LABEL: func @matmul(%{{.*}}: !linalg.buffer<?xf32>, %{{.*}}: index, %{{.*}}: index, %{{.*}}: index) {
-// CHECK: %[[A:.*]] = linalg.view %arg0[{{.*}}] : !linalg.buffer<?xf32> -> !linalg.view<?x?xf32>
-// CHECK: %[[B:.*]] = linalg.view %arg0[{{.*}}] : !linalg.buffer<?xf32> -> !linalg.view<?x?xf32>
-// CHECK: %[[C:.*]] = linalg.view %arg0[{{.*}}] : !linalg.buffer<?xf32> -> !linalg.view<?x?xf32>
-// CHECK: %[[M:.*]] = linalg.dim %[[A]], 0 : !linalg.view<?x?xf32>
-// CHECK: %[[K:.*]] = linalg.dim %[[A]], 1 : !linalg.view<?x?xf32>
-// CHECK: %[[N:.*]] = linalg.dim %[[B]], 1 : !linalg.view<?x?xf32>
+// CHECK: %[[A:.*]] = linalg.view %arg0[{{.*}}] : !linalg.buffer<?xf32> -> memref<?x?xf32, #[[strided2D]]>
+// CHECK: %[[B:.*]] = linalg.view %arg0[{{.*}}] : !linalg.buffer<?xf32> -> memref<?x?xf32, #[[strided2D]]>
+// CHECK: %[[C:.*]] = linalg.view %arg0[{{.*}}] : !linalg.buffer<?xf32> -> memref<?x?xf32, #[[strided2D]]>
+// CHECK: %[[M:.*]] = dim %[[A]], 0 : memref<?x?xf32, #[[strided2D]]>
+// CHECK: %[[K:.*]] = dim %[[A]], 1 : memref<?x?xf32, #[[strided2D]]>
+// CHECK: %[[N:.*]] = dim %[[B]], 1 : memref<?x?xf32, #[[strided2D]]>
// CHECK: loop.for %{{.*}} = %{{.*}} to %[[M]] step %{{.*}} {
// CHECK: loop.for %{{.*}} = %{{.*}} to %[[N]] step %{{.*}} {
// CHECK: loop.for %{{.*}} = %{{.*}} to %[[K]] step %{{.*}} {
-// CHECK-DAG: %[[a:.*]] = linalg.load %[[A]][%{{.*}}, %{{.*}}] : !linalg.view<?x?xf32>
-// CHECK-DAG: %[[b:.*]] = linalg.load %[[B]][%{{.*}}, %{{.*}}] : !linalg.view<?x?xf32>
+// CHECK-DAG: %[[a:.*]] = load %[[A]][%{{.*}}, %{{.*}}] : memref<?x?xf32, #[[strided2D]]>
+// CHECK-DAG: %[[b:.*]] = load %[[B]][%{{.*}}, %{{.*}}] : memref<?x?xf32, #[[strided2D]]>
// CHECK-DAG: %[[inc:.*]] = mulf %[[a]], %[[b]] : f32
-// CHECK-DAG: %[[c:.*]] = linalg.load %[[C]][%{{.*}}, %{{.*}}] : !linalg.view<?x?xf32>
+// CHECK-DAG: %[[c:.*]] = load %[[C]][%{{.*}}, %{{.*}}] : memref<?x?xf32, #[[strided2D]]>
// CHECK-DAG: %[[res:.*]] = addf %[[c]], %[[inc]] : f32
-// CHECK: linalg.store %[[res]], %[[C]][%{{.*}}, %{{.*}}] : !linalg.view<?x?xf32>
+// CHECK: store %[[res]], %[[C]][%{{.*}}, %{{.*}}] : memref<?x?xf32, #[[strided2D]]>
func @matvec(%arg0: !linalg.buffer<?xf32>, %arg1: index, %arg2: index, %arg3: index) {
%c0 = constant 0 : index
%c1 = constant 1 : index
%I = linalg.range %c0:%arg1:%c1 : !linalg.range
%J = linalg.range %c0:%arg2:%c1 : !linalg.range
- %2 = linalg.view %arg0[%I, %J] : !linalg.buffer<?xf32> -> !linalg.view<?x?xf32>
- %3 = linalg.view %arg0[%J] : !linalg.buffer<?xf32> -> !linalg.view<?xf32>
- %4 = linalg.view %arg0[%I] : !linalg.buffer<?xf32> -> !linalg.view<?xf32>
- linalg.matvec(%2, %3, %4) : !linalg.view<?x?xf32>, !linalg.view<?xf32>, !linalg.view<?xf32>
+ %2 = linalg.view %arg0[%I, %J] : !linalg.buffer<?xf32> -> memref<?x?xf32, #strided2D>
+ %3 = linalg.view %arg0[%J] : !linalg.buffer<?xf32> -> memref<?xf32, #strided1D>
+ %4 = linalg.view %arg0[%I] : !linalg.buffer<?xf32> -> memref<?xf32, #strided1D>
+ linalg.matvec(%2, %3, %4) : memref<?x?xf32, #strided2D>, memref<?xf32, #strided1D>, memref<?xf32, #strided1D>
return
}
// CHECK-LABEL: func @matvec(%{{.*}}: !linalg.buffer<?xf32>, %{{.*}}: index, %{{.*}}: index, %{{.*}}: index) {
-// CHECK: %[[A:.*]] = linalg.view %arg0[{{.*}}] : !linalg.buffer<?xf32> -> !linalg.view<?x?xf32>
-// CHECK: %[[B:.*]] = linalg.view %arg0[{{.*}}] : !linalg.buffer<?xf32> -> !linalg.view<?xf32>
-// CHECK: %[[C:.*]] = linalg.view %arg0[{{.*}}] : !linalg.buffer<?xf32> -> !linalg.view<?xf32>
-// CHECK: %[[M:.*]] = linalg.dim %[[A]], 0 : !linalg.view<?x?xf32>
-// CHECK: %[[K:.*]] = linalg.dim %[[A]], 1 : !linalg.view<?x?xf32>
+// CHECK: %[[A:.*]] = linalg.view %arg0[{{.*}}] : !linalg.buffer<?xf32> -> memref<?x?xf32, #[[strided2D]]>
+// CHECK: %[[B:.*]] = linalg.view %arg0[{{.*}}] : !linalg.buffer<?xf32> -> memref<?xf32, #[[strided1D]]>
+// CHECK: %[[C:.*]] = linalg.view %arg0[{{.*}}] : !linalg.buffer<?xf32> -> memref<?xf32, #[[strided1D]]>
+// CHECK: %[[M:.*]] = dim %[[A]], 0 : memref<?x?xf32, #[[strided2D]]>
+// CHECK: %[[K:.*]] = dim %[[A]], 1 : memref<?x?xf32, #[[strided2D]]>
// CHECK: loop.for %{{.*}} = %{{.*}} to %[[M]] step %{{.*}} {
// CHECK: loop.for %{{.*}} = %{{.*}} to %[[K]] step %{{.*}} {
-// CHECK-DAG: %[[a:.*]] = linalg.load %[[A]][%{{.*}}, %{{.*}}] : !linalg.view<?x?xf32>
-// CHECK-DAG: %[[b:.*]] = linalg.load %[[B]][%{{.*}}] : !linalg.view<?xf32>
+// CHECK-DAG: %[[a:.*]] = load %[[A]][%{{.*}}, %{{.*}}] : memref<?x?xf32, #[[strided2D]]>
+// CHECK-DAG: %[[b:.*]] = load %[[B]][%{{.*}}] : memref<?xf32, #[[strided1D]]>
// CHECK-DAG: %[[inc:.*]] = mulf %[[a]], %[[b]] : f32
-// CHECK-DAG: %[[c:.*]] = linalg.load %[[C]][%{{.*}}] : !linalg.view<?xf32>
+// CHECK-DAG: %[[c:.*]] = load %[[C]][%{{.*}}] : memref<?xf32, #[[strided1D]]>
// CHECK-DAG: %[[res:.*]] = addf %[[c]], %[[inc]] : f32
-// CHECK: linalg.store %[[res]], %[[C]][%{{.*}}] : !linalg.view<?xf32>
+// CHECK: store %[[res]], %[[C]][%{{.*}}] : memref<?xf32, #[[strided1D]]>
func @dot(%arg0: !linalg.buffer<?xf32>, %arg1: index, %arg2: index, %arg3: index) {
%c0 = constant 0 : index
%c1 = constant 1 : index
%I = linalg.range %c0:%arg1:%c1 : !linalg.range
- %1 = linalg.view %arg0[%I] : !linalg.buffer<?xf32> -> !linalg.view<?xf32>
- %2 = linalg.view %arg0[%I] : !linalg.buffer<?xf32> -> !linalg.view<?xf32>
- %3 = linalg.view %arg0[] : !linalg.buffer<?xf32> -> !linalg.view<f32>
- linalg.dot(%1, %2, %3) : !linalg.view<?xf32>, !linalg.view<?xf32>, !linalg.view<f32>
+ %1 = linalg.view %arg0[%I] : !linalg.buffer<?xf32> -> memref<?xf32, #strided1D>
+ %2 = linalg.view %arg0[%I] : !linalg.buffer<?xf32> -> memref<?xf32, #strided1D>
+ %3 = linalg.view %arg0[] : !linalg.buffer<?xf32> -> memref<f32>
+ linalg.dot(%1, %2, %3) : memref<?xf32, #strided1D>, memref<?xf32, #strided1D>, memref<f32>
return
}
// CHECK-LABEL: func @dot(%{{.*}}: !linalg.buffer<?xf32>, %{{.*}}: index, %{{.*}}: index, %{{.*}}: index) {
-// CHECK: %[[A:.*]] = linalg.view %arg0[{{.*}}] : !linalg.buffer<?xf32> -> !linalg.view<?xf32>
-// CHECK: %[[B:.*]] = linalg.view %arg0[{{.*}}] : !linalg.buffer<?xf32> -> !linalg.view<?xf32>
-// CHECK: %[[C:.*]] = linalg.view %arg0[] : !linalg.buffer<?xf32> -> !linalg.view<f32>
-// CHECK: %[[K:.*]] = linalg.dim %[[A]], 0 : !linalg.view<?xf32>
+// CHECK: %[[A:.*]] = linalg.view %arg0[{{.*}}] : !linalg.buffer<?xf32> -> memref<?xf32, #[[strided1D]]>
+// CHECK: %[[B:.*]] = linalg.view %arg0[{{.*}}] : !linalg.buffer<?xf32> -> memref<?xf32, #[[strided1D]]>
+// CHECK: %[[C:.*]] = linalg.view %arg0[] : !linalg.buffer<?xf32> -> memref<f32>
+// CHECK: %[[K:.*]] = dim %[[A]], 0 : memref<?xf32, #[[strided1D]]>
// CHECK: loop.for %{{.*}} = %{{.*}} to %[[K]] step %{{.*}} {
-// CHECK-DAG: %[[a:.*]] = linalg.load %[[A]][%{{.*}}] : !linalg.view<?xf32>
-// CHECK-DAG: %[[b:.*]] = linalg.load %[[B]][%{{.*}}] : !linalg.view<?xf32>
+// CHECK-DAG: %[[a:.*]] = load %[[A]][%{{.*}}] : memref<?xf32, #[[strided1D]]>
+// CHECK-DAG: %[[b:.*]] = load %[[B]][%{{.*}}] : memref<?xf32, #[[strided1D]]>
// CHECK-DAG: %[[inc:.*]] = mulf %[[a]], %[[b]] : f32
-// CHECK-DAG: %[[c:.*]] = linalg.load %[[C]][] : !linalg.view<f32>
+// CHECK-DAG: %[[c:.*]] = load %[[C]][] : memref<f32>
// CHECK-DAG: %[[res:.*]] = addf %[[c]], %[[inc]] : f32
-// CHECK: linalg.store %[[res]], %[[C]][] : !linalg.view<f32>
+// CHECK: store %[[res]], %[[C]][] : memref<f32>
-func @dot_view(%arg0: !linalg.view<?xf32>, %arg1: !linalg.view<?xf32>, %arg2: !linalg.view<f32>) {
- linalg.dot(%arg0, %arg1, %arg2) : !linalg.view<?xf32>, !linalg.view<?xf32>, !linalg.view<f32>
+func @dot_view(%arg0: memref<?xf32, #strided1D>, %arg1: memref<?xf32, #strided1D>, %arg2: memref<f32>) {
+ linalg.dot(%arg0, %arg1, %arg2) : memref<?xf32, #strided1D>, memref<?xf32, #strided1D>, memref<f32>
return
}
-// CHECK-LABEL: func @dot_view(%{{.*}}: !linalg.view<?xf32>, %{{.*}}: !linalg.view<?xf32>, %{{.*}}: !linalg.view<f32>) {
-// CHECK: %[[K:.*]] = linalg.dim %arg0, 0 : !linalg.view<?xf32>
+// CHECK-LABEL: func @dot_view(
+// CHECK: %{{.*}}: memref<?xf32, #[[strided1D]]>, %{{.*}}: memref<?xf32, #[[strided1D]]>, %{{.*}}: memref<f32>) {
+// CHECK: %[[K:.*]] = dim %arg0, 0 : memref<?xf32, #[[strided1D]]>
// CHECK: loop.for %{{.*}} = %{{.*}} to %[[K]] step %{{.*}} {
-// CHECK-DAG: %[[a:.*]] = linalg.load %arg0[%{{.*}}] : !linalg.view<?xf32>
-// CHECK-DAG: %[[b:.*]] = linalg.load %{{.*}}[%{{.*}}] : !linalg.view<?xf32>
+// CHECK-DAG: %[[a:.*]] = load %arg0[%{{.*}}] : memref<?xf32, #[[strided1D]]>
+// CHECK-DAG: %[[b:.*]] = load %{{.*}}[%{{.*}}] : memref<?xf32, #[[strided1D]]>
// CHECK-DAG: %[[inc:.*]] = mulf %[[a]], %[[b]] : f32
-// CHECK-DAG: %[[c:.*]] = linalg.load %{{.*}}[] : !linalg.view<f32>
+// CHECK-DAG: %[[c:.*]] = load %{{.*}}[] : memref<f32>
// CHECK-DAG: %[[res:.*]] = addf %[[c]], %[[inc]] : f32
-// CHECK: linalg.store %[[res]], %{{.*}}[] : !linalg.view<f32>
+// CHECK: store %[[res]], %{{.*}}[] : memref<f32>
-func @fill_view(%arg0: !linalg.view<?xf32>, %arg1: f32) {
- linalg.fill(%arg0, %arg1) : !linalg.view<?xf32>, f32
+func @fill_view(%arg0: memref<?xf32, #strided1D>, %arg1: f32) {
+ linalg.fill(%arg0, %arg1) : memref<?xf32, #strided1D>, f32
return
}
-// CHECK-LABEL: func @fill_view(%{{.*}}: !linalg.view<?xf32>, %{{.*}}: f32) {
+// CHECK-LABEL: func @fill_view(
+// CHECK: %{{.*}}: memref<?xf32, #[[strided1D]]>, %{{.*}}: f32) {
// CHECK: loop.for %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} {
-// CHECK: linalg.store %{{.*}}, %{{.*}}[%{{.*}}] : !linalg.view<?xf32>
+// CHECK: store %{{.*}}, %{{.*}}[%{{.*}}] : memref<?xf32, #[[strided1D]]>
-func @fill_view0(%arg0: !linalg.view<f32>, %arg1: f32) {
- linalg.fill(%arg0, %arg1) : !linalg.view<f32>, f32
+func @fill_view0(%arg0: memref<f32>, %arg1: f32) {
+ linalg.fill(%arg0, %arg1) : memref<f32>, f32
return
}
-// CHECK-LABEL: func @fill_view0(%{{.*}}: !linalg.view<f32>, %{{.*}}: f32) {
-// CHECK: linalg.store %{{.*}}, %{{.*}}[] : !linalg.view<f32>
+// CHECK-LABEL: func @fill_view0(%{{.*}}: memref<f32>, %{{.*}}: f32) {
+// CHECK: store %{{.*}}, %{{.*}}[] : memref<f32>
-func @fill_view3(%arg0: !linalg.view<?x?x?xf32>, %arg1: f32) {
- linalg.fill(%arg0, %arg1) : !linalg.view<?x?x?xf32>, f32
+func @fill_view3(%arg0: memref<?x?x?xf32, #strided3D>, %arg1: f32) {
+ linalg.fill(%arg0, %arg1) : memref<?x?x?xf32, #strided3D>, f32
return
}
-// CHECK-LABEL: func @fill_view3(%{{.*}}: !linalg.view<?x?x?xf32>, %{{.*}}: f32) {
+// CHECK-LABEL: func @fill_view3(
+// CHECK: %{{.*}}: memref<?x?x?xf32, #[[strided3D]]>, %{{.*}}: f32) {
// CHECK: loop.for %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} {
// CHECK: loop.for %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} {
// CHECK: loop.for %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} {
-// CHECK: linalg.store %{{.*}}, %{{.*}}[%{{.*}}, %{{.*}}, %{{.*}}] : !linalg.view<?x?x?xf32>
+// CHECK: store %{{.*}}, %{{.*}}[%{{.*}}, %{{.*}}, %{{.*}}] : memref<?x?x?xf32, #[[strided3D]]>
-func @copy_view(%arg0: !linalg.view<?xf32>, %arg1: !linalg.view<?xf32>) {
- linalg.copy(%arg0, %arg1) : !linalg.view<?xf32>, !linalg.view<?xf32>
+func @copy_view(%arg0: memref<?xf32, #strided1D>, %arg1: memref<?xf32, #strided1D>) {
+ linalg.copy(%arg0, %arg1) : memref<?xf32, #strided1D>, memref<?xf32, #strided1D>
return
}
-// CHECK-LABEL: func @copy_view(%{{.*}}: !linalg.view<?xf32>, %{{.*}}: !linalg.view<?xf32>) {
+// CHECK-LABEL: func @copy_view(
+// CHECK: %{{.*}}: memref<?xf32, #[[strided1D]]>, %{{.*}}: memref<?xf32, #[[strided1D]]>) {
// CHECK: loop.for %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} {
-// CHECK: %[[L:.*]] = linalg.load %{{.*}}[%{{.*}}] : !linalg.view<?xf32>
-// CHECK: linalg.store %[[L]], %{{.*}}[%{{.*}}] : !linalg.view<?xf32>
+// CHECK: %[[L:.*]] = load %{{.*}}[%{{.*}}] : memref<?xf32, #[[strided1D]]>
+// CHECK: store %[[L]], %{{.*}}[%{{.*}}] : memref<?xf32, #[[strided1D]]>
-func @copy_view0(%arg0: !linalg.view<f32>, %arg1: !linalg.view<f32>) {
- linalg.copy(%arg0, %arg1) : !linalg.view<f32>, !linalg.view<f32>
+func @copy_view0(%arg0: memref<f32>, %arg1: memref<f32>) {
+ linalg.copy(%arg0, %arg1) : memref<f32>, memref<f32>
return
}
-// CHECK-LABEL: func @copy_view0(%{{.*}}: !linalg.view<f32>, %{{.*}}: !linalg.view<f32>) {
-// CHECK: %{{.*}} = linalg.load %{{.*}}[] : !linalg.view<f32>
-// CHECK: linalg.store %{{.*}}, %{{.*}}[] : !linalg.view<f32>
+// CHECK-LABEL: func @copy_view0(%{{.*}}: memref<f32>, %{{.*}}: memref<f32>) {
+// CHECK: %{{.*}} = load %{{.*}}[] : memref<f32>
+// CHECK: store %{{.*}}, %{{.*}}[] : memref<f32>
-func @copy_view3(%arg0: !linalg.view<?x?x?xf32>, %arg1: !linalg.view<?x?x?xf32>) {
+func @copy_view3(%arg0: memref<?x?x?xf32, #strided3D>, %arg1: memref<?x?x?xf32, #strided3D>) {
linalg.copy(%arg0, %arg1) {inputPermutation = (i, j, k) -> (i, k, j),
outputPermutation = (i, j, k) -> (k, j, i)} :
- !linalg.view<?x?x?xf32>, !linalg.view<?x?x?xf32>
+ memref<?x?x?xf32, #strided3D>, memref<?x?x?xf32, #strided3D>
return
}
-// CHECK-LABEL: func @copy_view3(%{{.*}}: !linalg.view<?x?x?xf32>, %{{.*}}: !linalg.view<?x?x?xf32>) {
+// CHECK-LABEL: func @copy_view3
+// CHECK: (%{{.*}}: memref<?x?x?xf32, #[[strided3D]]>, %{{.*}}: memref<?x?x?xf32, #[[strided3D]]>) {
// CHECK: loop.for %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} {
// CHECK: loop.for %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} {
// CHECK: loop.for %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} {
-// CHECK: %[[L:.*]] = linalg.load %{{.*}}[%{{.*}}, %{{.*}}, %{{.*}}] : !linalg.view<?x?x?xf32>
-// CHECK: linalg.store %[[L]], %{{.*}}[%{{.*}}, %{{.*}}, %{{.*}}] : !linalg.view<?x?x?xf32>
+// CHECK: %[[L:.*]] = load %{{.*}}[%{{.*}}, %{{.*}}, %{{.*}}] : memref<?x?x?xf32, #[[strided3D]]>
+// CHECK: store %[[L]], %{{.*}}[%{{.*}}, %{{.*}}, %{{.*}}] : memref<?x?x?xf32, #[[strided3D]]>
-func @conv_view3(%arg0: !linalg.view<?x?x?xf32>, %arg1: !linalg.view<?x?x?xf32>, %arg2: !linalg.view<?x?x?xf32>) {
- linalg.conv(%arg0, %arg1, %arg2) {strides = [2]}: !linalg.view<?x?x?xf32>, !linalg.view<?x?x?xf32>, !linalg.view<?x?x?xf32>
+func @conv_view3(%arg0: memref<?x?x?xf32, #strided3D>, %arg1: memref<?x?x?xf32, #strided3D>, %arg2: memref<?x?x?xf32, #strided3D>) {
+ linalg.conv(%arg0, %arg1, %arg2) {strides = [2]}: memref<?x?x?xf32, #strided3D>, memref<?x?x?xf32, #strided3D>, memref<?x?x?xf32, #strided3D>
return
}
-// CHECK-LABEL: func @conv_view3(%{{.*}}: !linalg.view<?x?x?xf32>, %{{.*}}: !linalg.view<?x?x?xf32>, %{{.*}}: !linalg.view<?x?x?xf32>) {
-// CHECK: %[[Z0:.*]] = linalg.dim %arg0, 0 : !linalg.view<?x?x?xf32>
-// CHECK: %[[Q:.*]] = linalg.dim %arg0, 1 : !linalg.view<?x?x?xf32>
-// CHECK: %[[K:.*]] = linalg.dim %arg0, 2 : !linalg.view<?x?x?xf32>
-// CHECK: %[[B:.*]] = linalg.dim %arg1, 0 : !linalg.view<?x?x?xf32>
-// CHECK: %[[X0:.*]] = linalg.dim %arg2, 1 : !linalg.view<?x?x?xf32>
+// CHECK-LABEL: func @conv_view3(
+// CHECK: %{{.*}}: memref<?x?x?xf32, #[[strided3D]]>, %{{.*}}: memref<?x?x?xf32, #[[strided3D]]>, %{{.*}}: memref<?x?x?xf32, #[[strided3D]]>) {
+// CHECK: %[[Z0:.*]] = dim %arg0, 0 : memref<?x?x?xf32, #[[strided3D]]>
+// CHECK: %[[Q:.*]] = dim %arg0, 1 : memref<?x?x?xf32, #[[strided3D]]>
+// CHECK: %[[K:.*]] = dim %arg0, 2 : memref<?x?x?xf32, #[[strided3D]]>
+// CHECK: %[[B:.*]] = dim %arg1, 0 : memref<?x?x?xf32, #[[strided3D]]>
+// CHECK: %[[X0:.*]] = dim %arg2, 1 : memref<?x?x?xf32, #[[strided3D]]>
// CHECK: loop.for %{{.*}} = %{{.*}} to %[[B]] step %{{.*}} {
// CHECK: loop.for %{{.*}} = %{{.*}} to %[[X0]] step %{{.*}} {
// CHECK: loop.for %{{.*}} = %{{.*}} to %[[K]] step %{{.*}} {
// CHECK: loop.for %{{.*}} = %{{.*}} to %[[Q]] step %{{.*}} {
// CHECK: loop.for %{{.*}} = %{{.*}} to %[[Z0]] step %{{.*}} {
-// CHECK: %[[SUM:.*]] = affine.apply #[[S2D1]](%{{.*}}, %{{.*}})
-// CHECK: %{{.*}} = linalg.load %{{.*}}[%{{.*}}, %[[SUM]], %{{.*}}] : !linalg.view<?x?x?xf32>
-// CHECK: %{{.*}} = linalg.load %{{.*}}[%{{.*}}, %{{.*}}, %{{.*}}] : !linalg.view<?x?x?xf32>
+// CHECK: %[[SUM:.*]] = affine.apply #[[Stride2Dilation1]](%{{.*}}, %{{.*}})
+// CHECK: %{{.*}} = load %{{.*}}[%{{.*}}, %[[SUM]], %{{.*}}] : memref<?x?x?xf32, #[[strided3D]]>
+// CHECK: %{{.*}} = load %{{.*}}[%{{.*}}, %{{.*}}, %{{.*}}] : memref<?x?x?xf32, #[[strided3D]]>
// CHECK: %{{.*}} = mulf %{{.*}}, %{{.*}} : f32
-// CHECK: %{{.*}} = linalg.load %{{.*}}[%{{.*}}, %{{.*}}, %{{.*}}] : !linalg.view<?x?x?xf32>
+// CHECK: %{{.*}} = load %{{.*}}[%{{.*}}, %{{.*}}, %{{.*}}] : memref<?x?x?xf32, #[[strided3D]]>
// CHECK: %{{.*}} = addf %{{.*}}, %{{.*}} : f32
-// CHECK: linalg.store %{{.*}}, %{{.*}}[%{{.*}}, %{{.*}}, %{{.*}}] : !linalg.view<?x?x?xf32>
+// CHECK: store %{{.*}}, %{{.*}}[%{{.*}}, %{{.*}}, %{{.*}}] : memref<?x?x?xf32, #[[strided3D]]>
-func @conv_view4(%arg0: !linalg.view<?x?x?x?xf32>, %arg1: !linalg.view<?x?x?x?xf32>, %arg2: !linalg.view<?x?x?x?xf32>) {
- linalg.conv(%arg0, %arg1, %arg2) {dilations = [4, 5], strides = [2, 3]} : !linalg.view<?x?x?x?xf32>, !linalg.view<?x?x?x?xf32>, !linalg.view<?x?x?x?xf32>
+func @conv_view4(%arg0: memref<?x?x?x?xf32, #strided4D>, %arg1: memref<?x?x?x?xf32, #strided4D>, %arg2: memref<?x?x?x?xf32, #strided4D>) {
+ linalg.conv(%arg0, %arg1, %arg2) {dilations = [4, 5], strides = [2, 3]} : memref<?x?x?x?xf32, #strided4D>, memref<?x?x?x?xf32, #strided4D>, memref<?x?x?x?xf32, #strided4D>
return
}
-// CHECK-LABEL: func @conv_view4(%{{.*}}: !linalg.view<?x?x?x?xf32>, %{{.*}}: !linalg.view<?x?x?x?xf32>, %{{.*}}: !linalg.view<?x?x?x?xf32>) {
-// CHECK: %[[Z0:.*]] = linalg.dim %arg0, 0 : !linalg.view<?x?x?x?xf32>
-// CHECK: %[[Z1:.*]] = linalg.dim %arg0, 1 : !linalg.view<?x?x?x?xf32>
-// CHECK: %[[Q:.*]] = linalg.dim %arg0, 2 : !linalg.view<?x?x?x?xf32>
-// CHECK: %[[K:.*]] = linalg.dim %arg0, 3 : !linalg.view<?x?x?x?xf32>
-// CHECK: %[[B:.*]] = linalg.dim %arg1, 0 : !linalg.view<?x?x?x?xf32>
-// CHECK: %[[X0:.*]] = linalg.dim %arg2, 1 : !linalg.view<?x?x?x?xf32>
-// CHECK: %[[X1:.*]] = linalg.dim %arg2, 2 : !linalg.view<?x?x?x?xf32>
+// CHECK-LABEL: func @conv_view4(
+// CHECK: %{{.*}}: memref<?x?x?x?xf32, #[[strided4D]]>, %{{.*}}: memref<?x?x?x?xf32, #[[strided4D]]>, %{{.*}}: memref<?x?x?x?xf32, #[[strided4D]]>) {
+// CHECK: %[[Z0:.*]] = dim %arg0, 0 : memref<?x?x?x?xf32, #[[strided4D]]>
+// CHECK: %[[Z1:.*]] = dim %arg0, 1 : memref<?x?x?x?xf32, #[[strided4D]]>
+// CHECK: %[[Q:.*]] = dim %arg0, 2 : memref<?x?x?x?xf32, #[[strided4D]]>
+// CHECK: %[[K:.*]] = dim %arg0, 3 : memref<?x?x?x?xf32, #[[strided4D]]>
+// CHECK: %[[B:.*]] = dim %arg1, 0 : memref<?x?x?x?xf32, #[[strided4D]]>
+// CHECK: %[[X0:.*]] = dim %arg2, 1 : memref<?x?x?x?xf32, #[[strided4D]]>
+// CHECK: %[[X1:.*]] = dim %arg2, 2 : memref<?x?x?x?xf32, #[[strided4D]]>
// CHECK: loop.for %{{.*}} = %{{.*}} to %[[B]] step %{{.*}} {
// CHECK: loop.for %{{.*}} = %{{.*}} to %[[X0]] step %{{.*}} {
// CHECK: loop.for %{{.*}} = %{{.*}} to %[[X1]] step %{{.*}} {
// CHECK: loop.for %{{.*}} = %{{.*}} to %[[Q]] step %{{.*}} {
// CHECK: loop.for %{{.*}} = %{{.*}} to %[[Z0]] step %{{.*}} {
// CHECK: loop.for %{{.*}} = %{{.*}} to %[[Z1]] step %{{.*}} {
-// CHECK: %[[SUM0:.*]] = affine.apply #map1(%{{.*}}, %{{.*}})
-// CHECK: %[[SUM1:.*]] = affine.apply #map2(%{{.*}}, %{{.*}})
-// CHECK: %{{.*}} = linalg.load %{{.*}}[%{{.*}}, %[[SUM0]], %[[SUM1]], %{{.*}}] : !linalg.view<?x?x?x?xf32>
-// CHECK: %{{.*}} = linalg.load %{{.*}}[%{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}] : !linalg.view<?x?x?x?xf32>
+// CHECK: %[[SUM0:.*]] = affine.apply #[[Stride2Dilation4]](%{{.*}}, %{{.*}})
+// CHECK: %[[SUM1:.*]] = affine.apply #[[Stride3Dilation5]](%{{.*}}, %{{.*}})
+// CHECK: %{{.*}} = load %{{.*}}[%{{.*}}, %[[SUM0]], %[[SUM1]], %{{.*}}] : memref<?x?x?x?xf32, #[[strided4D]]>
+// CHECK: %{{.*}} = load %{{.*}}[%{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}] : memref<?x?x?x?xf32, #[[strided4D]]>
// CHECK: %{{.*}} = mulf %{{.*}}, %{{.*}} : f32
-// CHECK: %{{.*}} = linalg.load %{{.*}}[%{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}] : !linalg.view<?x?x?x?xf32>
+// CHECK: %{{.*}} = load %{{.*}}[%{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}] : memref<?x?x?x?xf32, #[[strided4D]]>
// CHECK: %{{.*}} = addf %{{.*}}, %{{.*}} : f32
-// CHECK: linalg.store %{{.*}}, %{{.*}}[%{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}] : !linalg.view<?x?x?x?xf32>
+// CHECK: store %{{.*}}, %{{.*}}[%{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}] : memref<?x?x?x?xf32, #[[strided4D]]>
func @foo(%0: f32, %1: f32, %2: f32) -> (f32, f32) {
%f0 = constant 0.0 : f32
library_call = "external_function_name",
doc = "B(i,j,k), C(i,k,j) = foo(A(i, j), B(i,j,k), C(i,k,j))"
}
-func @generic_function(%arg0: !linalg.view<?x?xf32>, %arg1: !linalg.view<?x?x?xf32>, %arg2: !linalg.view<?x?x?xf32>) {
+func @generic_function(%arg0: memref<?x?xf32, #strided2D>, %arg1: memref<?x?x?xf32, #strided3D>, %arg2: memref<?x?x?xf32, #strided3D>) {
linalg.generic #trait %arg0, %arg1, %arg2:
- !linalg.view<?x?xf32>, !linalg.view<?x?x?xf32>, !linalg.view<?x?x?xf32>
+ memref<?x?xf32, #strided2D>, memref<?x?x?xf32, #strided3D>, memref<?x?x?xf32, #strided3D>
return
}
// CHECK-LABEL: @foo
// CHECK: loop.for %[[i:.*]] = {{.*}}
// CHECK: loop.for %[[j:.*]] = {{.*}}
// CHECK: loop.for %[[k:.*]] = {{.*}}
-// CHECK: %[[a:.*]] = linalg.load %{{.*}}[%[[i]], %[[j]]] : !linalg.view<?x?xf32>
-// CHECK: %[[b:.*]] = linalg.load %{{.*}}[%[[i]], %[[j]], %[[k]]] : !linalg.view<?x?x?xf32>
-// CHECK: %[[c:.*]] = linalg.load %{{.*}}[%[[i]], %[[k]], %[[j]]] : !linalg.view<?x?x?xf32>
+// CHECK: %[[a:.*]] = load %{{.*}}[%[[i]], %[[j]]] : memref<?x?xf32, #[[strided2D]]>
+// CHECK: %[[b:.*]] = load %{{.*}}[%[[i]], %[[j]], %[[k]]] : memref<?x?x?xf32, #[[strided3D]]>
+// CHECK: %[[c:.*]] = load %{{.*}}[%[[i]], %[[k]], %[[j]]] : memref<?x?x?xf32, #[[strided3D]]>
// CHECK: %[[res:.*]]:2 = call @foo(%[[a]], %[[b]], %[[c]]) : (f32, f32, f32) -> (f32, f32)
-// CHECK: linalg.store %[[res]]#0, %{{.*}}[%[[i]], %[[j]], %[[k]]] : !linalg.view<?x?x?xf32>
-// CHECK: linalg.store %[[res]]#1, %{{.*}}[%[[i]], %[[k]], %[[j]]] : !linalg.view<?x?x?xf32>
+// CHECK: store %[[res]]#0, %{{.*}}[%[[i]], %[[j]], %[[k]]] : memref<?x?x?xf32, #[[strided3D]]>
+// CHECK: store %[[res]]#1, %{{.*}}[%[[i]], %[[k]], %[[j]]] : memref<?x?x?xf32, #[[strided3D]]>
#trait2 = {
n_views = [1, 2],
library_call = "external_function_name",
doc = "B(i,j,k), C(i,k,j) = foo(A(i, j), B(i,j,k), C(i,k,j))"
}
-func @generic_region(%arg0: !linalg.view<?x?xf32>, %arg1: !linalg.view<?x?x?xf32>, %arg2: !linalg.view<?x?x?xf32>) {
+func @generic_region(%arg0: memref<?x?xf32, #strided2D>, %arg1: memref<?x?x?xf32, #strided3D>, %arg2: memref<?x?x?xf32, #strided3D>) {
linalg.generic #trait2 %arg0, %arg1, %arg2 {
^bb0(%a: f32, %b: f32, %c: f32):
%d = mulf %a, %b : f32
%e = addf %c, %d : f32
linalg.yield %d, %e : f32, f32
- }: !linalg.view<?x?xf32>, !linalg.view<?x?x?xf32>, !linalg.view<?x?x?xf32>
+ }: memref<?x?xf32, #strided2D>, memref<?x?x?xf32, #strided3D>, memref<?x?x?xf32, #strided3D>
return
}
// CHECK-LABEL: @generic_region
// CHECK: loop.for %[[i:.*]] = {{.*}}
// CHECK: loop.for %[[j:.*]] = {{.*}}
// CHECK: loop.for %[[k:.*]] = {{.*}}
-// CHECK: %[[a:.*]] = linalg.load %{{.*}}[%[[i]], %[[j]]] : !linalg.view<?x?xf32>
-// CHECK: %[[b:.*]] = linalg.load %{{.*}}[%[[i]], %[[j]], %[[k]]] : !linalg.view<?x?x?xf32>
-// CHECK: %[[c:.*]] = linalg.load %{{.*}}[%[[i]], %[[k]], %[[j]]] : !linalg.view<?x?x?xf32>
+// CHECK: %[[a:.*]] = load %{{.*}}[%[[i]], %[[j]]] : memref<?x?xf32, #[[strided2D]]>
+// CHECK: %[[b:.*]] = load %{{.*}}[%[[i]], %[[j]], %[[k]]] : memref<?x?x?xf32, #[[strided3D]]>
+// CHECK: %[[c:.*]] = load %{{.*}}[%[[i]], %[[k]], %[[j]]] : memref<?x?x?xf32, #[[strided3D]]>
// CHECK: %[[d:.*]] = mulf %[[a]], %[[b]] : f32
// CHECK: %[[e:.*]] = addf %[[c]], %[[d]] : f32
-// CHECK: linalg.store %[[d]], %{{.*}}[%[[i]], %[[j]], %[[k]]] : !linalg.view<?x?x?xf32>
-// CHECK: linalg.store %[[e]], %{{.*}}[%[[i]], %[[k]], %[[j]]] : !linalg.view<?x?x?xf32>
+// CHECK: store %[[d]], %{{.*}}[%[[i]], %[[j]], %[[k]]] : memref<?x?x?xf32, #[[strided3D]]>
+// CHECK: store %[[e]], %{{.*}}[%[[i]], %[[k]], %[[j]]] : memref<?x?x?xf32, #[[strided3D]]>
// RUN: mlir-opt %s -linalg-tile -linalg-tile-sizes=2,3,4 -linalg-tile-promote-full-tile-views=true | FileCheck %s -check-prefix=TILE-1D
+// TILE-1D-DAG: #[[strided2D:.*]] = (d0, d1)[s0, s1] -> (d0 * s1 + s0 + d1)
+// TILE-1D-DAG: #[[strided2DnoOffset:.*]] = (d0, d1)[s0] -> (d0 * s0 + d1)
+#strided2D = (d0, d1)[s0, s1] -> (d0 * s1 + s0 + d1)
+
func @matmul(%arg0: !linalg.buffer<?xf32>, %arg1: index, %arg2: index, %arg3: index) {
%c0 = constant 0 : index
%c1 = constant 1 : index
%I = linalg.range %c0:%arg1:%c1 : !linalg.range
%J = linalg.range %c0:%arg2:%c1 : !linalg.range
%K = linalg.range %c0:%arg3:%c1 : !linalg.range
- %A = linalg.view %arg0[%I, %K] : !linalg.buffer<?xf32> -> !linalg.view<?x?xf32>
- %B = linalg.view %arg0[%K, %J] : !linalg.buffer<?xf32> -> !linalg.view<?x?xf32>
- %C = linalg.view %arg0[%I, %J] : !linalg.buffer<?xf32> -> !linalg.view<?x?xf32>
- linalg.matmul(%A, %B, %C) : !linalg.view<?x?xf32>, !linalg.view<?x?xf32>, !linalg.view<?x?xf32>
+ %A = linalg.view %arg0[%I, %K] : !linalg.buffer<?xf32> -> memref<?x?xf32, #strided2D>
+ %B = linalg.view %arg0[%K, %J] : !linalg.buffer<?xf32> -> memref<?x?xf32, #strided2D>
+ %C = linalg.view %arg0[%I, %J] : !linalg.buffer<?xf32> -> memref<?x?xf32, #strided2D>
+ linalg.matmul(%A, %B, %C) : memref<?x?xf32, #strided2D>, memref<?x?xf32, #strided2D>, memref<?x?xf32, #strided2D>
return
}
// TILE-1D-LABEL: func @matmul(%{{.*}}: !linalg.buffer<?xf32>, %{{.*}}: index, %{{.*}}: index, %{{.*}}: index) {
// TILE-1D: loop.for %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} {
// TILE-1D: loop.for %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} {
// TILE-1D: loop.for %{{.*}} = %{{.*}} to %{{.*}} step %{{.*}} {
-// TILE-1D: %[[vA:.*]] = linalg.subview {{.*}} : !linalg.view<?x?xf32>
-// TILE-1D: %[[vB:.*]] = linalg.subview {{.*}} : !linalg.view<?x?xf32>
-// TILE-1D: %[[vC:.*]] = linalg.subview {{.*}} : !linalg.view<?x?xf32>
+// TILE-1D: %[[vA:.*]] = linalg.subview {{.*}} : memref<?x?xf32, #[[strided2D]]>
+// TILE-1D: %[[vB:.*]] = linalg.subview {{.*}} : memref<?x?xf32, #[[strided2D]]>
+// TILE-1D: %[[vC:.*]] = linalg.subview {{.*}} : memref<?x?xf32, #[[strided2D]]>
///
// TILE-1D: %[[tmpA:.*]] = linalg.buffer_alloc : !linalg.buffer<8xf32>
-// TILE-1D: %[[fullA:.*]] = linalg.view %[[tmpA]][{{.*}}] : !linalg.buffer<8xf32> -> !linalg.view<?x?xf32>
-// TILE-1D: %[[partialA:.*]] = linalg.slice %[[fullA]][%{{.*}}, %{{.*}}] : !linalg.view<?x?xf32>, !linalg.range, !linalg.range, !linalg.view<?x?xf32>
+// TILE-1D: %[[fullA:.*]] = linalg.view %[[tmpA]][{{.*}}] : !linalg.buffer<8xf32> -> memref<?x?xf32>
+// TILE-1D: %[[partialA:.*]] = linalg.slice %[[fullA]][%{{.*}}, %{{.*}}] : memref<?x?xf32>, !linalg.range, !linalg.range, memref<?x?xf32, #[[strided2DnoOffset]]>
///
// TILE-1D: %[[tmpB:.*]] = linalg.buffer_alloc : !linalg.buffer<12xf32>
-// TILE-1D: %[[fullB:.*]] = linalg.view %[[tmpB]][{{.*}}] : !linalg.buffer<12xf32> -> !linalg.view<?x?xf32>
-// TILE-1D: %[[partialB:.*]] = linalg.slice %[[fullB]][%{{.*}}, %{{.*}}] : !linalg.view<?x?xf32>, !linalg.range, !linalg.range, !linalg.view<?x?xf32>
+// TILE-1D: %[[fullB:.*]] = linalg.view %[[tmpB]][{{.*}}] : !linalg.buffer<12xf32> -> memref<?x?xf32>
+// TILE-1D: %[[partialB:.*]] = linalg.slice %[[fullB]][%{{.*}}, %{{.*}}] : memref<?x?xf32>, !linalg.range, !linalg.range, memref<?x?xf32, #[[strided2DnoOffset]]>
///
// TILE-1D: %[[tmpC:.*]] = linalg.buffer_alloc : !linalg.buffer<6xf32>
-// TILE-1D: %[[fullC:.*]] = linalg.view %[[tmpC]][{{.*}}] : !linalg.buffer<6xf32> -> !linalg.view<?x?xf32>
-// TILE-1D: %[[partialC:.*]] = linalg.slice %[[fullC]][%{{.*}}, %{{.*}}] : !linalg.view<?x?xf32>, !linalg.range, !linalg.range, !linalg.view<?x?xf32>
+// TILE-1D: %[[fullC:.*]] = linalg.view %[[tmpC]][{{.*}}] : !linalg.buffer<6xf32> -> memref<?x?xf32>
+// TILE-1D: %[[partialC:.*]] = linalg.slice %[[fullC]][%{{.*}}, %{{.*}}] : memref<?x?xf32>, !linalg.range, !linalg.range, memref<?x?xf32, #[[strided2DnoOffset]]>
-// TILE-1D: linalg.fill(%[[fullA]], {{.*}}) : !linalg.view<?x?xf32>, f32
-// TILE-1D: linalg.fill(%[[fullB]], {{.*}}) : !linalg.view<?x?xf32>, f32
-// TILE-1D: linalg.fill(%[[fullC]], {{.*}}) : !linalg.view<?x?xf32>, f32
-// TILE-1D: linalg.copy(%[[vA]], %[[partialA]]) : !linalg.view<?x?xf32>, !linalg.view<?x?xf32>
-// TILE-1D: linalg.copy(%[[vB]], %[[partialB]]) : !linalg.view<?x?xf32>, !linalg.view<?x?xf32>
-// TILE-1D: linalg.copy(%[[vC]], %[[partialC]]) : !linalg.view<?x?xf32>, !linalg.view<?x?xf32>
+// TILE-1D: linalg.fill(%[[fullA]], {{.*}}) : memref<?x?xf32>, f32
+// TILE-1D: linalg.fill(%[[fullB]], {{.*}}) : memref<?x?xf32>, f32
+// TILE-1D: linalg.fill(%[[fullC]], {{.*}}) : memref<?x?xf32>, f32
+// TILE-1D: linalg.copy(%[[vA]], %[[partialA]]) : memref<?x?xf32, #[[strided2D]]>, memref<?x?xf32, #[[strided2DnoOffset]]>
+// TILE-1D: linalg.copy(%[[vB]], %[[partialB]]) : memref<?x?xf32, #[[strided2D]]>, memref<?x?xf32, #[[strided2DnoOffset]]>
+// TILE-1D: linalg.copy(%[[vC]], %[[partialC]]) : memref<?x?xf32, #[[strided2D]]>, memref<?x?xf32, #[[strided2DnoOffset]]>
//
-// TILE-1D: linalg.matmul(%[[fullA]], %[[fullB]], %[[fullC]]) : !linalg.view<?x?xf32>, !linalg.view<?x?xf32>, !linalg.view<?x?xf32>
+// TILE-1D: linalg.matmul(%[[fullA]], %[[fullB]], %[[fullC]]) : memref<?x?xf32>, memref<?x?xf32>, memref<?x?xf32>
//
-// TILE-1D: linalg.copy(%[[partialC]], %[[vC]]) : !linalg.view<?x?xf32>, !linalg.view<?x?xf32>
+// TILE-1D: linalg.copy(%[[partialC]], %[[vC]]) : memref<?x?xf32, #[[strided2DnoOffset]]>, memref<?x?xf32, #[[strided2D]]>
//
// TILE-1D: linalg.buffer_dealloc %[[tmpA]] : !linalg.buffer<8xf32>
// TILE-1D: linalg.buffer_dealloc %[[tmpB]] : !linalg.buffer<12xf32>
// RUN: mlir-opt %s | mlir-opt | FileCheck %s
+// CHECK-DAG: #[[strided1D:.*]] = (d0)[s0] -> (d0 + s0)
+#strided1D = (d0)[s0] -> (d0 + s0)
+// CHECK-DAG: #[[strided2D:.*]] = (d0, d1)[s0, s1] -> (d0 * s1 + s0 + d1)
+#strided2D = (d0, d1)[s0, s1] -> (d0 * s1 + s0 + d1)
+// CHECK-DAG: #[[strided3D:.*]] = (d0, d1, d2)[s0, s1, s2] -> (d0 * s1 + s0 + d1 * s2 + d2)
+#strided3D = (d0, d1, d2)[s0, s1, s2] -> (d0 * s1 + s0 + d1 * s2 + d2)
+// CHECK-DAG: #[[strided6D:.*]] = (d0, d1, d2, d3, d4, d5)[s0, s1, s2, s3, s4, s5, s6] -> (d0 * s1 + s0 + d1 * s2 + d2 * s3 + d3 * s4 + d4 * s5 + d5 * s6)
+#strided6D = (d0, d1, d2, d3, d4, d5)[s0, s1, s2, s3, s4, s5, s6] -> (d0 * s1 + s0 + d1 * s2 + d2 * s3 + d3 * s4 + d4 * s5 + d5 * s6)
+
// CHECK-DAG: #[[map0:.*]] = (d0, d1, d2) -> (d0, d2, d1)
// CHECK-DAG: #[[map1:.*]] = (d0, d1, d2) -> (d2, d1, d0)
// CHECK-NEXT: linalg.buffer_dealloc %{{.*}} : !linalg.buffer<?xvector<4xi8>>
// CHECK-NEXT: linalg.buffer_dealloc %{{.*}} : !linalg.buffer<?xvector<4xi8>>
-func @view_fun(%arg0: !linalg.view<?x?xvector<3x4xi4>>) {
- return
-}
-// CHECK-LABEL: func @view_fun(%{{.*}}: !linalg.view<?x?xvector<3x4xi4>>) {
-
func @views(%arg0: index, %arg1: index, %arg2: index, %arg3: index, %arg4: index) {
%0 = muli %arg0, %arg0 : index
%1 = linalg.buffer_alloc %0 : !linalg.buffer<?xf32>
%2 = linalg.range %arg2:%arg3:%arg4 : !linalg.range
- %3 = linalg.view %1[%2, %2] : !linalg.buffer<?xf32> -> !linalg.view<?x?xf32>
- %4 = linalg.slice %3[%2, %2] : !linalg.view<?x?xf32>, !linalg.range, !linalg.range, !linalg.view<?x?xf32>
- %5 = linalg.slice %3[%2, %arg2] : !linalg.view<?x?xf32>, !linalg.range, index, !linalg.view<?xf32>
- %6 = linalg.slice %3[%arg2, %2] : !linalg.view<?x?xf32>, index, !linalg.range, !linalg.view<?xf32>
- %7 = linalg.slice %3[%arg2, %arg3] : !linalg.view<?x?xf32>, index, index, !linalg.view<f32>
- %8 = linalg.view %1[%2, %2] : !linalg.buffer<?xf32> -> !linalg.view<?x?xvector<4x4xf32>>
+ %3 = linalg.view %1[%2, %2] : !linalg.buffer<?xf32> -> memref<?x?xf32, #strided2D>
+ %4 = linalg.slice %3[%2, %2] : memref<?x?xf32, #strided2D>, !linalg.range, !linalg.range, memref<?x?xf32, #strided2D>
+ %5 = linalg.slice %3[%2, %arg2] : memref<?x?xf32, #strided2D>, !linalg.range, index, memref<?xf32, #strided1D>
+ %6 = linalg.slice %3[%arg2, %2] : memref<?x?xf32, #strided2D>, index, !linalg.range, memref<?xf32, #strided1D>
+ %7 = linalg.slice %3[%arg2, %arg3] : memref<?x?xf32, #strided2D>, index, index, memref<f32>
+ %8 = linalg.view %1[%2, %2] : !linalg.buffer<?xf32> -> memref<?x?xvector<4x4xf32>, #strided2D>
linalg.buffer_dealloc %1 : !linalg.buffer<?xf32>
return
}
// CHECK-NEXT: muli %{{.*}}, %{{.*}} : index
// CHECK-NEXT: linalg.buffer_alloc %{{.*}} : !linalg.buffer<?xf32>
// CHECK-NEXT: linalg.range %{{.*}}:%{{.*}}:%{{.*}} : !linalg.range
-// CHECK-NEXT: linalg.view %{{.*}}[%{{.*}}, %{{.*}}] : !linalg.buffer<?xf32> -> !linalg.view<?x?xf32>
-// CHECK-NEXT: linalg.slice %{{.*}}[%{{.*}}, %{{.*}}] : !linalg.view<?x?xf32>, !linalg.range, !linalg.range, !linalg.view<?x?xf32>
-// CHECK-NEXT: linalg.slice %{{.*}}[%{{.*}}, %{{.*}}] : !linalg.view<?x?xf32>, !linalg.range, index, !linalg.view<?xf32>
-// CHECK-NEXT: linalg.slice %{{.*}}[%{{.*}}, %{{.*}}] : !linalg.view<?x?xf32>, index, !linalg.range, !linalg.view<?xf32>
-// CHECK-NEXT: linalg.slice %{{.*}}[%{{.*}}, %{{.*}}] : !linalg.view<?x?xf32>, index, index, !linalg.view<f32>
-// CHECK-NEXT: linalg.view %{{.*}}[%{{.*}}, %{{.*}}] : !linalg.buffer<?xf32> -> !linalg.view<?x?xvector<4x4xf32>>
+// CHECK-NEXT: linalg.view %{{.*}}[%{{.*}}, %{{.*}}] : !linalg.buffer<?xf32> -> memref<?x?xf32, #[[strided2D]]>
+// CHECK-NEXT: linalg.slice %{{.*}}[%{{.*}}, %{{.*}}] : memref<?x?xf32, #[[strided2D]]>, !linalg.range, !linalg.range, memref<?x?xf32, #[[strided2D]]>
+// CHECK-NEXT: linalg.slice %{{.*}}[%{{.*}}, %{{.*}}] : memref<?x?xf32, #[[strided2D]]>, !linalg.range, index, memref<?xf32, #[[strided1D]]>
+// CHECK-NEXT: linalg.slice %{{.*}}[%{{.*}}, %{{.*}}] : memref<?x?xf32, #[[strided2D]]>, index, !linalg.range, memref<?xf32, #[[strided1D]]>
+// CHECK-NEXT: linalg.slice %{{.*}}[%{{.*}}, %{{.*}}] : memref<?x?xf32, #[[strided2D]]>, index, index, memref<f32>
+// CHECK-NEXT: linalg.view %{{.*}}[%{{.*}}, %{{.*}}] : !linalg.buffer<?xf32> -> memref<?x?xvector<4x4xf32>, #[[strided2D]]>
// CHECK-NEXT: linalg.buffer_dealloc %{{.*}} : !linalg.buffer<?xf32>
-func @ops(%arg0: !linalg.view<?x?xf32>, %arg1: !linalg.view<?xf32>, %arg2: !linalg.view<?xf32>, %arg3: !linalg.view<f32>) {
- linalg.matmul(%arg0, %arg0, %arg0) : !linalg.view<?x?xf32>, !linalg.view<?x?xf32>, !linalg.view<?x?xf32>
- linalg.matvec(%arg0, %arg1, %arg2) : !linalg.view<?x?xf32>, !linalg.view<?xf32>, !linalg.view<?xf32>
- linalg.dot(%arg1, %arg2, %arg3) : !linalg.view<?xf32>, !linalg.view<?xf32>, !linalg.view<f32>
+func @ops(%arg0: memref<?x?xf32, #strided2D>, %arg1: memref<?xf32, #strided1D>, %arg2: memref<?xf32, #strided1D>, %arg3: memref<f32>) {
+ linalg.matmul(%arg0, %arg0, %arg0) : memref<?x?xf32, #strided2D>, memref<?x?xf32, #strided2D>, memref<?x?xf32, #strided2D>
+ linalg.matvec(%arg0, %arg1, %arg2) : memref<?x?xf32, #strided2D>, memref<?xf32, #strided1D>, memref<?xf32, #strided1D>
+ linalg.dot(%arg1, %arg2, %arg3) : memref<?xf32, #strided1D>, memref<?xf32, #strided1D>, memref<f32>
return
}
-// CHECK-LABEL: func @ops(%{{.*}}: !linalg.view<?x?xf32>, %{{.*}}: !linalg.view<?xf32>, %{{.*}}: !linalg.view<?xf32>, %{{.*}}: !linalg.view<f32>) {
-// CHECK-NEXT: linalg.matmul(%{{.*}}, %{{.*}}, %{{.*}}) : !linalg.view<?x?xf32>, !linalg.view<?x?xf32>, !linalg.view<?x?xf32>
-// CHECK-NEXT: linalg.matvec(%{{.*}}, %{{.*}}, %{{.*}}) : !linalg.view<?x?xf32>, !linalg.view<?xf32>, !linalg.view<?xf32>
-// CHECK-NEXT: linalg.dot(%{{.*}}, %{{.*}}, %{{.*}}) : !linalg.view<?xf32>, !linalg.view<?xf32>, !linalg.view<f32>
+// CHECK-LABEL: func @ops(%
+// CHECK: {{.*}}: memref<?x?xf32, #[[strided2D]]>, %{{.*}}: memref<?xf32, #[[strided1D]]>, %{{.*}}: memref<?xf32, #[[strided1D]]>, %{{.*}}: memref<f32>) {
+// CHECK-NEXT: linalg.matmul(%{{.*}}, %{{.*}}, %{{.*}}) : memref<?x?xf32, #[[strided2D]]>, memref<?x?xf32, #[[strided2D]]>, memref<?x?xf32, #[[strided2D]]>
+// CHECK-NEXT: linalg.matvec(%{{.*}}, %{{.*}}, %{{.*}}) : memref<?x?xf32, #[[strided2D]]>, memref<?xf32, #[[strided1D]]>, memref<?xf32, #[[strided1D]]>
+// CHECK-NEXT: linalg.dot(%{{.*}}, %{{.*}}, %{{.*}}) : memref<?xf32, #[[strided1D]]>, memref<?xf32, #[[strided1D]]>, memref<f32>
-func @dim(%arg0: !linalg.view<?x?xf32>) {
- %0 = linalg.dim %arg0, 1 : !linalg.view<?x?xf32>
+func @dim(%arg0: memref<?x?xf32, #strided2D>) {
+ %0 = dim %arg0, 1 : memref<?x?xf32, #strided2D>
%1 = linalg.buffer_alloc %0 : !linalg.buffer<?xf32>
linalg.buffer_dealloc %1 : !linalg.buffer<?xf32>
return
}
-// CHECK-LABEL: func @dim(%{{.*}}: !linalg.view<?x?xf32>) {
-// CHECK-NEXT: linalg.dim %{{.*}}, 1 : !linalg.view<?x?xf32>
+// CHECK-LABEL: func @dim(
+// CHECK: %{{.*}}: memref<?x?xf32, #[[strided2D]]>) {
+// CHECK-NEXT: dim %{{.*}}, 1 : memref<?x?xf32, #[[strided2D]]>
// CHECK-NEXT: linalg.buffer_alloc %{{.*}} : !linalg.buffer<?xf32>
// CHECK-NEXT: linalg.buffer_dealloc %{{.*}} : !linalg.buffer<?xf32>
}
return
}
-// CHECK-LABEL: func @linalg_for(%{{.*}}: index, %{{.*}}: index, %{{.*}}: index) {
+// CHECK-LABEL: func @linalg_for(
+// CHECK: %{{.*}}: index, %{{.*}}: index, %{{.*}}: index) {
// CHECK-NEXT: loop.for %{{.*}} to %{{.*}} step %{{.*}} {
// CHECK-NEXT: loop.for %{{.*}} to %{{.*}} step %{{.*}} {
// CHECK-NEXT: cmpi "slt", %{{.*}}, %{{.*}} : index
// CHECK-NEXT: select %{{.*}}, %{{.*}}, %{{.*}} : index
// CHECK-NEXT: loop.for %{{.*}} to %{{.*}} step %{{.*}} {
-func @fill_view(%arg0: !linalg.view<?xf32>, %arg1: f32) {
- linalg.fill(%arg0, %arg1) : !linalg.view<?xf32>, f32
+func @fill_view(%arg0: memref<?xf32, #strided1D>, %arg1: f32) {
+ linalg.fill(%arg0, %arg1) : memref<?xf32, #strided1D>, f32
return
}
-// CHECK-LABEL: func @fill_view(%{{.*}}: !linalg.view<?xf32>, %{{.*}}: f32) {
-// CHECK: linalg.fill(%{{.*}}, %{{.*}}) : !linalg.view<?xf32>, f32
+// CHECK-LABEL: func @fill_view(
+// CHECK: %{{.*}}: memref<?xf32, #[[strided1D]]>, %{{.*}}: f32) {
+// CHECK: linalg.fill(%{{.*}}, %{{.*}}) : memref<?xf32, #[[strided1D]]>, f32
-func @transpose(%arg0: !linalg.view<?x?x?xf32>) {
- %0 = linalg.transpose %arg0 (i, j, k) -> (k, j, i) : !linalg.view<?x?x?xf32>
+func @transpose(%arg0: memref<?x?x?xf32, #strided3D>) {
+ %0 = linalg.transpose %arg0 (i, j, k) -> (k, j, i) : memref<?x?x?xf32, #strided3D>
return
}
// CHECK-LABEL: func @transpose
-// CHECK: linalg.transpose %{{.*}} ([[i:.*]], [[j:.*]], [[k:.*]]) -> ([[k]], [[j]], [[i]]) : !linalg.view<?x?x?xf32>
+// CHECK: linalg.transpose %{{.*}} ([[i:.*]], [[j:.*]], [[k:.*]]) -> ([[k]], [[j]], [[i]]) : memref<?x?x?xf32, #[[strided3D]]>
-func @fill_view3(%arg0: !linalg.view<?x?x?xf32>, %arg1: f32) {
- linalg.fill(%arg0, %arg1) : !linalg.view<?x?x?xf32>, f32
+func @fill_view3(%arg0: memref<?x?x?xf32, #strided3D>, %arg1: f32) {
+ linalg.fill(%arg0, %arg1) : memref<?x?x?xf32, #strided3D>, f32
return
}
-// CHECK-LABEL: func @fill_view3(%{{.*}}: !linalg.view<?x?x?xf32>, %{{.*}}: f32) {
-// CHECK: linalg.fill(%{{.*}}, %{{.*}}) : !linalg.view<?x?x?xf32>, f32
+// CHECK-LABEL: func @fill_view3(
+// CHECK: %{{.*}}: memref<?x?x?xf32, #[[strided3D]]>, %{{.*}}: f32) {
+// CHECK: linalg.fill(%{{.*}}, %{{.*}}) : memref<?x?x?xf32, #[[strided3D]]>, f32
-func @copy_view(%arg0: !linalg.view<?xf32>, %arg1: !linalg.view<?xf32>) {
- linalg.copy(%arg0, %arg1) : !linalg.view<?xf32>, !linalg.view<?xf32>
+func @copy_view(%arg0: memref<?xf32, #strided1D>, %arg1: memref<?xf32, #strided1D>) {
+ linalg.copy(%arg0, %arg1) : memref<?xf32, #strided1D>, memref<?xf32, #strided1D>
return
}
-// CHECK-LABEL: func @copy_view(%{{.*}}: !linalg.view<?xf32>, %{{.*}}: !linalg.view<?xf32>) {
-// CHECK: linalg.copy(%{{.*}}, %{{.*}}) : !linalg.view<?xf32>, !linalg.view<?xf32>
+// CHECK-LABEL: func @copy_view(
+// CHECK: %{{.*}}: memref<?xf32, #[[strided1D]]>, %{{.*}}: memref<?xf32, #[[strided1D]]>) {
+// CHECK: linalg.copy(%{{.*}}, %{{.*}}) : memref<?xf32, #[[strided1D]]>, memref<?xf32, #[[strided1D]]>
-func @copy_view3(%arg0: !linalg.view<?x?x?xf32>, %arg1: !linalg.view<?x?x?xf32>) {
+func @copy_view3(%arg0: memref<?x?x?xf32, #strided3D>, %arg1: memref<?x?x?xf32, #strided3D>) {
linalg.copy(%arg0, %arg1) {inputPermutation = (i, j, k) -> (i, k, j),
outputPermutation = (i, j, k) -> (k, j, i)} :
- !linalg.view<?x?x?xf32>, !linalg.view<?x?x?xf32>
+ memref<?x?x?xf32, #strided3D>, memref<?x?x?xf32, #strided3D>
return
}
-// CHECK-LABEL: func @copy_view3(%{{.*}}: !linalg.view<?x?x?xf32>, %{{.*}}: !linalg.view<?x?x?xf32>) {
-// CHECK: linalg.copy(%{{.*}}, %{{.*}}) {inputPermutation = #[[map0]], outputPermutation = #[[map1]]} : !linalg.view<?x?x?xf32>, !linalg.view<?x?x?xf32>
+// CHECK-LABEL: func @copy_view3(
+// CHECK: %{{.*}}: memref<?x?x?xf32, #[[strided3D]]>, %{{.*}}: memref<?x?x?xf32, #[[strided3D]]>) {
+// CHECK: linalg.copy(%{{.*}}, %{{.*}}) {inputPermutation = #[[map0]], outputPermutation = #[[map1]]} : memref<?x?x?xf32, #[[strided3D]]>, memref<?x?x?xf32, #[[strided3D]]>
-func @conv_view3(%arg0: !linalg.view<?x?x?xf32>, %arg1: !linalg.view<?x?x?xf32>, %arg2: !linalg.view<?x?x?xf32>) {
- linalg.conv(%arg0, %arg1, %arg2) : !linalg.view<?x?x?xf32>, !linalg.view<?x?x?xf32>, !linalg.view<?x?x?xf32>
+func @conv_view3(%arg0: memref<?x?x?xf32, #strided3D>, %arg1: memref<?x?x?xf32, #strided3D>, %arg2: memref<?x?x?xf32, #strided3D>) {
+ linalg.conv(%arg0, %arg1, %arg2) : memref<?x?x?xf32, #strided3D>, memref<?x?x?xf32, #strided3D>, memref<?x?x?xf32, #strided3D>
return
}
-// CHECK-LABEL: func @conv_view3(%{{.*}}: !linalg.view<?x?x?xf32>, %{{.*}}: !linalg.view<?x?x?xf32>, %{{.*}}: !linalg.view<?x?x?xf32>) {
-// CHECK: linalg.conv(%{{.*}}, %{{.*}}, %{{.*}}) : !linalg.view<?x?x?xf32>, !linalg.view<?x?x?xf32>, !linalg.view<?x?x?xf32>
+// CHECK-LABEL: func @conv_view3(
+// CHECK: %{{.*}}: memref<?x?x?xf32, #[[strided3D]]>, %{{.*}}: memref<?x?x?xf32, #[[strided3D]]>, %{{.*}}: memref<?x?x?xf32, #[[strided3D]]>) {
+// CHECK: linalg.conv(%{{.*}}, %{{.*}}, %{{.*}}) : memref<?x?x?xf32, #[[strided3D]]>, memref<?x?x?xf32, #[[strided3D]]>, memref<?x?x?xf32, #[[strided3D]]>
-func @conv_view6(%arg0: !linalg.view<?x?x?x?x?x?xf32>, %arg1: !linalg.view<?x?x?x?x?x?xf32>, %arg2: !linalg.view<?x?x?x?x?x?xf32>) {
- linalg.conv(%arg0, %arg1, %arg2) {dilations = [4, 4, 5, 5], strides = [2, 2, 3, 3]} : !linalg.view<?x?x?x?x?x?xf32>, !linalg.view<?x?x?x?x?x?xf32>, !linalg.view<?x?x?x?x?x?xf32>
+func @conv_view6(%arg0: memref<?x?x?x?x?x?xf32, #strided6D>, %arg1: memref<?x?x?x?x?x?xf32, #strided6D>, %arg2: memref<?x?x?x?x?x?xf32, #strided6D>) {
+ linalg.conv(%arg0, %arg1, %arg2) {dilations = [4, 4, 5, 5], strides = [2, 2, 3, 3]} : memref<?x?x?x?x?x?xf32, #strided6D>, memref<?x?x?x?x?x?xf32, #strided6D>, memref<?x?x?x?x?x?xf32, #strided6D>
return
}
-// CHECK-LABEL: func @conv_view6(%{{.*}}: !linalg.view<?x?x?x?x?x?xf32>, %{{.*}}: !linalg.view<?x?x?x?x?x?xf32>, %{{.*}}: !linalg.view<?x?x?x?x?x?xf32>) {
-// CHECK: linalg.conv(%{{.*}}, %{{.*}}, %{{.*}}) {dilations = [4, 4, 5, 5], strides = [2, 2, 3, 3]} : !linalg.view<?x?x?x?x?x?xf32>, !linalg.view<?x?x?x?x?x?xf32>, !linalg.view<?x?x?x?x?x?xf32>
+// CHECK-LABEL: func @conv_view6(
+// CHECK: %{{.*}}: memref<?x?x?x?x?x?xf32, #[[strided6D]]>, %{{.*}}: memref<?x?x?x?x?x?xf32, #[[strided6D]]>, %{{.*}}: memref<?x?x?x?x?x?xf32, #[[strided6D]]>) {
+// CHECK: linalg.conv(%{{.*}}, %{{.*}}, %{{.*}}) {dilations = [4, 4, 5, 5], strides = [2, 2, 3, 3]} : memref<?x?x?x?x?x?xf32, #[[strided6D]]>, memref<?x?x?x?x?x?xf32, #[[strided6D]]>, memref<?x?x?x?x?x?xf32, #[[strided6D]]>
-func @subview(%arg0: !linalg.view<?x?xvector<3x4xi4>>) {
+func @subview(%arg0: memref<?x?xvector<3x4xi4>, #strided2D>) {
%c0 = constant 0 : index
- %0 = linalg.subview %arg0[%c0, %c0, %c0, %c0, %c0, %c0] : !linalg.view<?x?xvector<3x4xi4>>
+ %0 = linalg.subview %arg0[%c0, %c0, %c0, %c0, %c0, %c0] : memref<?x?xvector<3x4xi4>, #strided2D>
return
}
-// CHECK-LABEL: func @subview(%{{.*}}: !linalg.view<?x?xvector<3x4xi4>>) {
+// CHECK-LABEL: func @subview(
+// CHECK: %{{.*}}: memref<?x?xvector<3x4xi4>, #[[strided2D]]>) {
// CHECK: constant 0 : index
-// CHECK: linalg.subview %{{.*}}[%{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}] : !linalg.view<?x?xvector<3x4xi4>>
+// CHECK: linalg.subview %{{.*}}[%{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}] : memref<?x?xvector<3x4xi4>, #[[strided2D]]>
func @const_buffer_view(%arg0: index, %arg1: index, %arg2: index) {
%c0 = linalg.buffer_alloc : !linalg.buffer<17xf32>
%c1 = linalg.range %arg0:%arg1:%arg2 : !linalg.range
- %c2 = linalg.view %c0[%c1] : !linalg.buffer<17xf32> -> !linalg.view<?xf32>
+ %c2 = linalg.view %c0[%c1] : !linalg.buffer<17xf32> -> memref<?xf32, #strided1D>
return
}
%f0 = constant 0.0 : f32
return %f0 : f32
}
-func @generic(%arg0: !linalg.view<?x?xvector<3x4xi4>>, %arg1: !linalg.view<?x?x?xf32>) {
- linalg.generic #trait %arg0, %arg1 {foo = 1} : !linalg.view<?x?xvector<3x4xi4>>, !linalg.view<?x?x?xf32>
+func @generic(%arg0: memref<?x?xvector<3x4xi4>, #strided2D>, %arg1: memref<?x?x?xf32, #strided3D>) {
+ linalg.generic #trait %arg0, %arg1 {foo = 1} : memref<?x?xvector<3x4xi4>, #strided2D>, memref<?x?x?xf32, #strided3D>
return
}
// CHECK-LABEL: func @foo
// CHECK-LABEL: func @generic
-// CHECK: linalg.generic {fun = @foo, indexing_maps = [#map2, #map3], library_call = "external_function_name", n_loop_types = [3, 0, 0], n_views = [1, 1]} %{{.*}}, %{{.*}} {foo = 1 : i64}: !linalg.view<?x?xvector<3x4xi4>>, !linalg.view<?x?x?xf32>
+// CHECK: linalg.generic {fun = @foo, indexing_maps = [#{{.*}}, #{{.*}}], library_call = "external_function_name", n_loop_types = [3, 0, 0], n_views = [1, 1]} %{{.*}}, %{{.*}} {foo = 1 : i64}: memref<?x?xvector<3x4xi4>, #[[strided2D]]>, memref<?x?x?xf32, #[[strided3D]]>
#trait2 = {
indexing_maps = #accesses,
n_loop_types = [3, 0, 0],
library_call = "external_function_name"
}
-func @generic_region(%arg0: !linalg.view<?x?xvector<3x4xi4>>, %arg1: !linalg.view<?x?x?xf32>) {
+func @generic_region(%arg0: memref<?x?xvector<3x4xi4>, #strided2D>, %arg1: memref<?x?x?xf32, #strided3D>) {
linalg.generic #trait2 %arg0, %arg1 {
^bb(%a: vector<3x4xi4>, %b: f32) :
linalg.yield %b : f32
- } {foo = 1}: !linalg.view<?x?xvector<3x4xi4>>, !linalg.view<?x?x?xf32>
+ } {foo = 1}: memref<?x?xvector<3x4xi4>, #strided2D>, memref<?x?x?xf32, #strided3D>
return
}
// CHECK-LABEL: func @generic_region
-// CHECK: linalg.generic {indexing_maps = [#map2, #map3], library_call = "external_function_name", n_loop_types = [3, 0, 0], n_views = [1, 1]} %{{.*}}, %{{.*}} {
+// CHECK: linalg.generic {indexing_maps = [#{{.*}}, #{{.*}}], library_call = "external_function_name", n_loop_types = [3, 0, 0], n_views = [1, 1]} %{{.*}}, %{{.*}} {
// CHECK: ^{{.*}}(%{{.*}}: vector<3x4xi4>, %{{.*}}: f32): // no predecessors
// CHECK: linalg.yield %{{.*}} : f32
-// CHECK: } {foo = 1 : i64}: !linalg.view<?x?xvector<3x4xi4>>, !linalg.view<?x?x?xf32>
\ No newline at end of file
+// CHECK: } {foo = 1 : i64}: memref<?x?xvector<3x4xi4>, #[[strided2D]]>, memref<?x?x?xf32, #[[strided3D]]>
// TILE-234-DAG: #[[UB1:.*]] = (d0) -> (d0 + 3)
// TILE-234-DAG: #[[UB2:.*]] = (d0) -> (d0 + 4)
-func @matmul(%arg0: !linalg.view<?x?xf32>, %arg1: !linalg.view<?x?xf32>, %arg2: !linalg.view<?x?xf32>) {
- linalg.matmul(%arg0, %arg1, %arg2) : !linalg.view<?x?xf32>, !linalg.view<?x?xf32>, !linalg.view<?x?xf32>
+// TILE-2-DAG: #[[strided1D:.*]] = (d0)[s0] -> (d0 + s0)
+// TILE-02-DAG: #[[strided1D:.*]] = (d0)[s0] -> (d0 + s0)
+// TILE-002-DAG: #[[strided1D:.*]] = (d0)[s0] -> (d0 + s0)
+// TILE-234-DAG: #[[strided1D:.*]] = (d0)[s0] -> (d0 + s0)
+#strided1D = (d0)[s0] -> (d0 + s0)
+// CHECK-DAG: #[[strided2D:.*]] = (d0, d1)[s0, s1] -> (d0 * s1 + s0 + d1)
+// TILE-2-DAG: #[[strided2D:.*]] = (d0, d1)[s0, s1] -> (d0 * s1 + s0 + d1)
+// TILE-02-DAG: #[[strided2D:.*]] = (d0, d1)[s0, s1] -> (d0 * s1 + s0 + d1)
+// TILE-002-DAG: #[[strided2D:.*]] = (d0, d1)[s0, s1] -> (d0 * s1 + s0 + d1)
+// TILE-234-DAG: #[[strided2D:.*]] = (d0, d1)[s0, s1] -> (d0 * s1 + s0 + d1)
+#strided2D = (d0, d1)[s0, s1] -> (d0 * s1 + s0 + d1)
+
+func @matmul(%arg0: memref<?x?xf32, #strided2D>, %arg1: memref<?x?xf32, #strided2D>, %arg2: memref<?x?xf32, #strided2D>) {
+ linalg.matmul(%arg0, %arg1, %arg2) : memref<?x?xf32, #strided2D>, memref<?x?xf32, #strided2D>, memref<?x?xf32, #strided2D>
return
}
-// TILE-2-LABEL: func @matmul(%{{.*}}: !linalg.view<?x?xf32>, %{{.*}}: !linalg.view<?x?xf32>, %{{.*}}: !linalg.view<?x?xf32>) {
-// TILE-2: %[[M:.*]] = linalg.dim %{{.*}}, 0 : !linalg.view<?x?xf32>
+// TILE-2-LABEL: func @matmul(
+// TILE-2: %[[M:.*]] = dim %{{.*}}, 0 : memref<?x?xf32, #[[strided2D]]>
// TILE-2: loop.for %{{.*}} = %{{.*}}{{.*}} to %[[M]] step %{{.*}} {
// TILE-2: %[[a:.*]] = affine.apply #[[UB0]](%{{.*}})
-// TILE-2: %[[K:.*]] = linalg.dim %{{.*}}, 1 : !linalg.view<?x?xf32>
-// TILE-2: %[[sAi:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[a]], %{{.*}}, %{{.*}}, %[[K]], %{{.*}}] : !linalg.view<?x?xf32>
+// TILE-2: %[[K:.*]] = dim %{{.*}}, 1 : memref<?x?xf32, #[[strided2D]]>
+// TILE-2: %[[sAi:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[a]], %{{.*}}, %{{.*}}, %[[K]], %{{.*}}] : memref<?x?xf32, #[[strided2D]]>
// TILE-2: %[[c:.*]] = affine.apply #[[UB0]](%{{.*}})
-// TILE-2: %[[N:.*]] = linalg.dim %{{.*}}, 1 : !linalg.view<?x?xf32>
-// TILE-2: %[[sCi:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[c]], %{{.*}}, %{{.*}}, %[[N]], %{{.*}}] : !linalg.view<?x?xf32>
-// TILE-2: linalg.matmul(%[[sAi]], %{{.*}}, %[[sCi]]) : !linalg.view<?x?xf32>, !linalg.view<?x?xf32>, !linalg.view<?x?xf32>
+// TILE-2: %[[N:.*]] = dim %{{.*}}, 1 : memref<?x?xf32, #[[strided2D]]>
+// TILE-2: %[[sCi:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[c]], %{{.*}}, %{{.*}}, %[[N]], %{{.*}}] : memref<?x?xf32, #[[strided2D]]>
+// TILE-2: linalg.matmul(%[[sAi]], %{{.*}}, %[[sCi]]) : memref<?x?xf32, #[[strided2D]]>, memref<?x?xf32, #[[strided2D]]>, memref<?x?xf32, #[[strided2D]]>
-// TILE-02-LABEL: func @matmul(%{{.*}}: !linalg.view<?x?xf32>, %{{.*}}: !linalg.view<?x?xf32>, %{{.*}}: !linalg.view<?x?xf32>) {
-// TILE-02: %[[N:.*]] = linalg.dim %arg1, 1 : !linalg.view<?x?xf32>
+// TILE-02-LABEL: func @matmul(
+// TILE-02: %[[N:.*]] = dim %arg1, 1 : memref<?x?xf32, #[[strided2D]]>
// TILE-02: loop.for %{{.*}} = %{{.*}} to %[[N]] step %{{.*}} {
-// TILE-02: %[[K:.*]] = linalg.dim %{{.*}}, 0 : !linalg.view<?x?xf32>
+// TILE-02: %[[K:.*]] = dim %{{.*}}, 0 : memref<?x?xf32, #[[strided2D]]>
// TILE-02: %[[b:.*]] = affine.apply #[[UB0]](%{{.*}})
-// TILE-02: %[[sBj:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[K]], %{{.*}}, %{{.*}}, %[[b]], %{{.*}}] : !linalg.view<?x?xf32>
-// TILE-02: %[[M:.*]] = linalg.dim %{{.*}}, 0 : !linalg.view<?x?xf32>
+// TILE-02: %[[sBj:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[K]], %{{.*}}, %{{.*}}, %[[b]], %{{.*}}] : memref<?x?xf32, #[[strided2D]]>
+// TILE-02: %[[M:.*]] = dim %{{.*}}, 0 : memref<?x?xf32, #[[strided2D]]>
// TILE-02: %[[c:.*]] = affine.apply #[[UB0]](%{{.*}})
-// TILE-02: %[[sCj:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[M]], %{{.*}}, %{{.*}}, %[[c]], %{{.*}}] : !linalg.view<?x?xf32>
-// TILE-02: linalg.matmul(%{{.*}}, %[[sBj]], %[[sCj]]) : !linalg.view<?x?xf32>, !linalg.view<?x?xf32>, !linalg.view<?x?xf32>
+// TILE-02: %[[sCj:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[M]], %{{.*}}, %{{.*}}, %[[c]], %{{.*}}] : memref<?x?xf32, #[[strided2D]]>
+// TILE-02: linalg.matmul(%{{.*}}, %[[sBj]], %[[sCj]]) : memref<?x?xf32, #[[strided2D]]>, memref<?x?xf32, #[[strided2D]]>, memref<?x?xf32, #[[strided2D]]>
-// TILE-002-LABEL: func @matmul(%{{.*}}: !linalg.view<?x?xf32>, %{{.*}}: !linalg.view<?x?xf32>, %{{.*}}: !linalg.view<?x?xf32>) {
-// TILE-002: %[[K:.*]] = linalg.dim %{{.*}}, 1 : !linalg.view<?x?xf32>
+// TILE-002-LABEL: func @matmul(
+// TILE-002: %[[K:.*]] = dim %{{.*}}, 1 : memref<?x?xf32, #[[strided2D]]>
// TILE-002: loop.for %{{.*}} = %{{.*}}{{.*}} to %[[K]] step %{{.*}} {
-// TILE-002: %[[M:.*]] = linalg.dim %{{.*}}, 0 : !linalg.view<?x?xf32>
+// TILE-002: %[[M:.*]] = dim %{{.*}}, 0 : memref<?x?xf32, #[[strided2D]]>
// TILE-002: %[[a:.*]] = affine.apply #[[UB0]](%{{.*}})
-// TILE-002: %[[sAj:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[M]], %{{.*}}, %{{.*}}, %[[a]], %{{.*}}] : !linalg.view<?x?xf32>
+// TILE-002: %[[sAj:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[M]], %{{.*}}, %{{.*}}, %[[a]], %{{.*}}] : memref<?x?xf32, #[[strided2D]]>
// TILE-002: %[[b:.*]] = affine.apply #[[UB0]](%{{.*}})
-// TILE-002: %[[N:.*]] = linalg.dim %{{.*}}, 1 : !linalg.view<?x?xf32>
-// TILE-002: %[[sBj:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[b]], %{{.*}}, %{{.*}}, %[[N]], %{{.*}}] : !linalg.view<?x?xf32>
-// TILE-002: linalg.matmul(%[[sAj]], %[[sBj]], %{{.*}}) : !linalg.view<?x?xf32>, !linalg.view<?x?xf32>, !linalg.view<?x?xf32>
-
-// TILE-234-LABEL: func @matmul(%{{.*}}: !linalg.view<?x?xf32>, %{{.*}}: !linalg.view<?x?xf32>, %{{.*}}: !linalg.view<?x?xf32>) {
-// TILE-234: %[[M:.*]] = linalg.dim %{{.*}}, 0 : !linalg.view<?x?xf32>
-// TILE-234: %[[K:.*]] = linalg.dim %{{.*}}, 1 : !linalg.view<?x?xf32>
-// TILE-234: %[[N:.*]] = linalg.dim %{{.*}}, 1 : !linalg.view<?x?xf32>
+// TILE-002: %[[N:.*]] = dim %{{.*}}, 1 : memref<?x?xf32, #[[strided2D]]>
+// TILE-002: %[[sBj:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[b]], %{{.*}}, %{{.*}}, %[[N]], %{{.*}}] : memref<?x?xf32, #[[strided2D]]>
+// TILE-002: linalg.matmul(%[[sAj]], %[[sBj]], %{{.*}}) : memref<?x?xf32, #[[strided2D]]>, memref<?x?xf32, #[[strided2D]]>, memref<?x?xf32, #[[strided2D]]>
+
+// TILE-234-LABEL: func @matmul(
+// TILE-234: %[[M:.*]] = dim %{{.*}}, 0 : memref<?x?xf32, #[[strided2D]]>
+// TILE-234: %[[K:.*]] = dim %{{.*}}, 1 : memref<?x?xf32, #[[strided2D]]>
+// TILE-234: %[[N:.*]] = dim %{{.*}}, 1 : memref<?x?xf32, #[[strided2D]]>
// TILE-234: loop.for %{{.*}} = %{{.*}}{{.*}} to %[[M]] step %{{.*}} {
// TILE-234: loop.for %{{.*}} = %{{.*}}{{.*}} to %[[N]] step %{{.*}} {
// TILE-234: loop.for %{{.*}} = %{{.*}}{{.*}} to %[[K]] step %{{.*}} {
// TILE-234: %[[ai:.*]] = affine.apply #[[UB0]](%{{.*}})
// TILE-234: %[[ak:.*]] = affine.apply #[[UB2]](%{{.*}})
-// TILE-234: %[[sAik:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[ai]], %{{.*}}, %{{.*}}, %[[ak]], %{{.*}}] : !linalg.view<?x?xf32>
+// TILE-234: %[[sAik:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[ai]], %{{.*}}, %{{.*}}, %[[ak]], %{{.*}}] : memref<?x?xf32, #[[strided2D]]>
// TILE-234: %[[bk:.*]] = affine.apply #[[UB2]](%{{.*}})
// TILE-234: %[[bj:.*]] = affine.apply #[[UB1]](%{{.*}})
-// TILE-234: %[[sBkj:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[bk]], %{{.*}}, %{{.*}}, %[[bj]], %{{.*}}] : !linalg.view<?x?xf32>
+// TILE-234: %[[sBkj:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[bk]], %{{.*}}, %{{.*}}, %[[bj]], %{{.*}}] : memref<?x?xf32, #[[strided2D]]>
// TILE-234: %[[ci:.*]] = affine.apply #[[UB0]](%{{.*}})
// TILE-234: %[[cj:.*]] = affine.apply #[[UB1]](%{{.*}})
-// TILE-234: %[[sCij:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[ci]], %{{.*}}, %{{.*}}, %[[cj]], %{{.*}}] : !linalg.view<?x?xf32>
+// TILE-234: %[[sCij:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[ci]], %{{.*}}, %{{.*}}, %[[cj]], %{{.*}}] : memref<?x?xf32, #[[strided2D]]>
//
-// TILE-234: linalg.matmul(%[[sAik]], %[[sBkj]], %[[sCij]]) : !linalg.view<?x?xf32>, !linalg.view<?x?xf32>, !linalg.view<?x?xf32>
+// TILE-234: linalg.matmul(%[[sAik]], %[[sBkj]], %[[sCij]]) : memref<?x?xf32, #[[strided2D]]>, memref<?x?xf32, #[[strided2D]]>, memref<?x?xf32, #[[strided2D]]>
-func @matvec(%arg0: !linalg.view<?x?xf32>, %arg1: !linalg.view<?xf32>, %arg2: !linalg.view<?xf32>) {
- linalg.matvec(%arg0, %arg1, %arg2) : !linalg.view<?x?xf32>, !linalg.view<?xf32>, !linalg.view<?xf32>
+func @matvec(%arg0: memref<?x?xf32, #strided2D>, %arg1: memref<?xf32, #strided1D>, %arg2: memref<?xf32, #strided1D>) {
+ linalg.matvec(%arg0, %arg1, %arg2) : memref<?x?xf32, #strided2D>, memref<?xf32, #strided1D>, memref<?xf32, #strided1D>
return
}
-// TILE-2-LABEL: func @matvec(%{{.*}}: !linalg.view<?x?xf32>, %{{.*}}: !linalg.view<?xf32>, %{{.*}}: !linalg.view<?xf32>) {
-// TILE-2: %[[M:.*]] = linalg.dim %{{.*}}, 0 : !linalg.view<?x?xf32>
+// TILE-2-LABEL: func @matvec(
+// TILE-2: %[[M:.*]] = dim %{{.*}}, 0 : memref<?x?xf32, #[[strided2D]]>
// TILE-2: loop.for %{{.*}} = %{{.*}}{{.*}} to %[[M]] step %{{.*}} {
// TILE-2: %[[a:.*]] = affine.apply #[[UB0]](%{{.*}})
-// TILE-2: %[[N:.*]] = linalg.dim %{{.*}}, 1 : !linalg.view<?x?xf32>
-// TILE-2: %[[sAi:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[a]], %{{.*}}, %{{.*}}, %[[N]], %{{.*}}] : !linalg.view<?x?xf32>
+// TILE-2: %[[N:.*]] = dim %{{.*}}, 1 : memref<?x?xf32, #[[strided2D]]>
+// TILE-2: %[[sAi:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[a]], %{{.*}}, %{{.*}}, %[[N]], %{{.*}}] : memref<?x?xf32, #[[strided2D]]>
// TILE-2: %[[c:.*]] = affine.apply #[[UB0]](%{{.*}})
-// TILE-2: %[[sCi:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[c]], %{{.*}}] : !linalg.view<?xf32>
-// TILE-2: linalg.matvec(%[[sAi]], %{{.*}}, %[[sCi]]) : !linalg.view<?x?xf32>, !linalg.view<?xf32>, !linalg.view<?xf32>
+// TILE-2: %[[sCi:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[c]], %{{.*}}] : memref<?xf32, #[[strided1D]]>
+// TILE-2: linalg.matvec(%[[sAi]], %{{.*}}, %[[sCi]]) : memref<?x?xf32, #[[strided2D]]>, memref<?xf32, #[[strided1D]]>, memref<?xf32, #[[strided1D]]>
-// TILE-02-LABEL: func @matvec(%{{.*}}: !linalg.view<?x?xf32>, %{{.*}}: !linalg.view<?xf32>, %{{.*}}: !linalg.view<?xf32>) {
-// TILE-02: %[[K:.*]] = linalg.dim %{{.*}}, 1 : !linalg.view<?x?xf32>
+// TILE-02-LABEL: func @matvec(
+// TILE-02: %[[K:.*]] = dim %{{.*}}, 1 : memref<?x?xf32, #[[strided2D]]>
// TILE-02: loop.for %{{.*}} = %{{.*}}{{.*}} to %[[K]] step %{{.*}} {
-// TILE-02: %[[M:.*]] = linalg.dim %{{.*}}, 0 : !linalg.view<?x?xf32>
+// TILE-02: %[[M:.*]] = dim %{{.*}}, 0 : memref<?x?xf32, #[[strided2D]]>
// TILE-02: %[[a:.*]] = affine.apply #[[UB0]](%{{.*}})
-// TILE-02: %[[sAj:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[M]], %{{.*}}, %{{.*}}, %[[a]], %{{.*}}] : !linalg.view<?x?xf32>
+// TILE-02: %[[sAj:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[M]], %{{.*}}, %{{.*}}, %[[a]], %{{.*}}] : memref<?x?xf32, #[[strided2D]]>
// TILE-02: %[[b:.*]] = affine.apply #[[UB0]](%{{.*}})
-// TILE-02: %[[sBj:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[b]], %{{.*}}] : !linalg.view<?xf32>
-// TILE-02: linalg.matvec(%[[sAj]], %[[sBj]], %{{.*}}) : !linalg.view<?x?xf32>, !linalg.view<?xf32>, !linalg.view<?xf32>
+// TILE-02: %[[sBj:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[b]], %{{.*}}] : memref<?xf32, #[[strided1D]]>
+// TILE-02: linalg.matvec(%[[sAj]], %[[sBj]], %{{.*}}) : memref<?x?xf32, #[[strided2D]]>, memref<?xf32, #[[strided1D]]>, memref<?xf32, #[[strided1D]]>
-// TILE-002-LABEL: func @matvec(%{{.*}}: !linalg.view<?x?xf32>, %{{.*}}: !linalg.view<?xf32>, %{{.*}}: !linalg.view<?xf32>) {
+// TILE-002-LABEL: func @matvec(
// TILE-002-NOT: loop.for
-// TILE-234-LABEL: func @matvec(%{{.*}}: !linalg.view<?x?xf32>, %{{.*}}: !linalg.view<?xf32>, %{{.*}}: !linalg.view<?xf32>) {
-// TILE-234: %[[M:.*]] = linalg.dim %{{.*}}, 0 : !linalg.view<?x?xf32>
-// TILE-234: %[[K:.*]] = linalg.dim %{{.*}}, 1 : !linalg.view<?x?xf32>
+// TILE-234-LABEL: func @matvec(
+// TILE-234: %[[M:.*]] = dim %{{.*}}, 0 : memref<?x?xf32, #[[strided2D]]>
+// TILE-234: %[[K:.*]] = dim %{{.*}}, 1 : memref<?x?xf32, #[[strided2D]]>
// TILE-234: loop.for %{{.*}} = %{{.*}}{{.*}} to %[[M]] step %{{.*}} {
// TILE-234: loop.for %{{.*}} = %{{.*}}{{.*}} to %[[K]] step %{{.*}} {
// TILE-234: %[[ai:.*]] = affine.apply #[[UB0]](%{{.*}})
// TILE-234: %[[aj:.*]] = affine.apply #[[UB1]](%{{.*}})
-// TILE-234: %[[sAij:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[ai]], %{{.*}}, %{{.*}}, %[[aj]], %{{.*}}] : !linalg.view<?x?xf32>
+// TILE-234: %[[sAij:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[ai]], %{{.*}}, %{{.*}}, %[[aj]], %{{.*}}] : memref<?x?xf32, #[[strided2D]]>
// TILE-234: %[[bj:.*]] = affine.apply #[[UB1]](%{{.*}})
-// TILE-234: %[[sBj:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[bj]], %{{.*}}] : !linalg.view<?xf32>
+// TILE-234: %[[sBj:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[bj]], %{{.*}}] : memref<?xf32, #[[strided1D]]>
// TILE-234: %[[ci:.*]] = affine.apply #[[UB0]](%{{.*}})
-// TILE-234: %[[sCi:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[ci]], %{{.*}}] : !linalg.view<?xf32>
+// TILE-234: %[[sCi:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[ci]], %{{.*}}] : memref<?xf32, #[[strided1D]]>
//
-// TILE-234: linalg.matvec(%[[sAij]], %[[sBj]], %[[sCi]]) : !linalg.view<?x?xf32>, !linalg.view<?xf32>, !linalg.view<?xf32>
+// TILE-234: linalg.matvec(%[[sAij]], %[[sBj]], %[[sCi]]) : memref<?x?xf32, #[[strided2D]]>, memref<?xf32, #[[strided1D]]>, memref<?xf32, #[[strided1D]]>
-func @dot(%arg0: !linalg.view<?xf32>, %arg1: !linalg.view<?xf32>, %arg2: !linalg.view<f32>) {
- linalg.dot(%arg0, %arg1, %arg2) : !linalg.view<?xf32>, !linalg.view<?xf32>, !linalg.view<f32>
+func @dot(%arg0: memref<?xf32, #strided1D>, %arg1: memref<?xf32, #strided1D>, %arg2: memref<f32>) {
+ linalg.dot(%arg0, %arg1, %arg2) : memref<?xf32, #strided1D>, memref<?xf32, #strided1D>, memref<f32>
return
}
-// TILE-2-LABEL: func @dot(%{{.*}}: !linalg.view<?xf32>, %{{.*}}: !linalg.view<?xf32>, %{{.*}}: !linalg.view<f32>) {
-// TILE-2: %[[M:.*]] = linalg.dim %{{.*}}, 0 : !linalg.view<?xf32>
+// TILE-2-LABEL: func @dot(
+// TILE-2: %[[M:.*]] = dim %{{.*}}, 0 : memref<?xf32, #[[strided1D]]>
// TILE-2: loop.for %{{.*}} = %{{.*}}{{.*}} to %[[M]] step %{{.*}} {
// TILE-2: %[[a:.*]] = affine.apply #[[UB0]](%{{.*}})
-// TILE-2: %[[sAi:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[a]], %{{.*}}] : !linalg.view<?xf32>
+// TILE-2: %[[sAi:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[a]], %{{.*}}] : memref<?xf32, #[[strided1D]]>
// TILE-2: %[[b:.*]] = affine.apply #[[UB0]](%{{.*}})
-// TILE-2: %[[sBi:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[b]], %{{.*}}] : !linalg.view<?xf32>
-// TILE-2: linalg.dot(%[[sAi]], %[[sBi]], {{.*}}) : !linalg.view<?xf32>, !linalg.view<?xf32>, !linalg.view<f32>
+// TILE-2: %[[sBi:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[b]], %{{.*}}] : memref<?xf32, #[[strided1D]]>
+// TILE-2: linalg.dot(%[[sAi]], %[[sBi]], {{.*}}) : memref<?xf32, #[[strided1D]]>, memref<?xf32, #[[strided1D]]>, memref<f32>
-// TILE-02-LABEL: func @dot(%{{.*}}: !linalg.view<?xf32>, %{{.*}}: !linalg.view<?xf32>, %{{.*}}: !linalg.view<f32>) {
+// TILE-02-LABEL: func @dot(
// TILE-02-NOT: loop.for
-// TILE-002-LABEL: func @dot(%{{.*}}: !linalg.view<?xf32>, %{{.*}}: !linalg.view<?xf32>, %{{.*}}: !linalg.view<f32>) {
+// TILE-002-LABEL: func @dot(
// TILE-002-NOT: loop.for
-// TILE-234-LABEL: func @dot(%{{.*}}: !linalg.view<?xf32>, %{{.*}}: !linalg.view<?xf32>, %{{.*}}: !linalg.view<f32>) {
-// TILE-234: %[[K:.*]] = linalg.dim %{{.*}}, 0 : !linalg.view<?xf32>
+// TILE-234-LABEL: func @dot(
+// TILE-234: %[[K:.*]] = dim %{{.*}}, 0 : memref<?xf32, #[[strided1D]]>
// TILE-234: loop.for %{{.*}} = %{{.*}}{{.*}} to %[[K]] step %{{.*}} {
// TILE-234: %[[a:.*]] = affine.apply #[[UB0]](%{{.*}})
-// TILE-234: %[[sAi:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[a]], %{{.*}}] : !linalg.view<?xf32>
+// TILE-234: %[[sAi:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[a]], %{{.*}}] : memref<?xf32, #[[strided1D]]>
// TILE-234: %[[b:.*]] = affine.apply #[[UB0]](%{{.*}})
-// TILE-234: %[[sBi:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[b]], %{{.*}}] : !linalg.view<?xf32>
-// TILE-234: linalg.dot(%[[sAi]], %[[sBi]], %{{.*}}) : !linalg.view<?xf32>, !linalg.view<?xf32>, !linalg.view<f32>
+// TILE-234: %[[sBi:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[b]], %{{.*}}] : memref<?xf32, #[[strided1D]]>
+// TILE-234: linalg.dot(%[[sAi]], %[[sBi]], %{{.*}}) : memref<?xf32, #[[strided1D]]>, memref<?xf32, #[[strided1D]]>, memref<f32>
-func @fill(%arg0: !linalg.view<?x?xf32>, %arg1: f32) {
- linalg.fill(%arg0, %arg1) : !linalg.view<?x?xf32>, f32
+func @fill(%arg0: memref<?x?xf32, #strided2D>, %arg1: f32) {
+ linalg.fill(%arg0, %arg1) : memref<?x?xf32, #strided2D>, f32
return
}
// TILE-2-LABEL: func @fill
n_views = [2, 1]
}
-func @pointwise(%arg0: !linalg.view<?x?xf32>, %arg1: !linalg.view<?x?xf32>,
- %arg2: !linalg.view<?x?xf32>) {
+func @pointwise(%arg0: memref<?x?xf32, #strided2D>, %arg1: memref<?x?xf32, #strided2D>,
+ %arg2: memref<?x?xf32, #strided2D>) {
linalg.generic #pointwise_2d_trait %arg0, %arg1, %arg2 {
^bb0(%arg4: f32, %arg5: f32, %arg6: f32): // no predecessors
%4 = addf %arg4, %arg5 : f32
linalg.yield %4 : f32
- }: !linalg.view<?x?xf32>, !linalg.view<?x?xf32>, !linalg.view<?x?xf32>
+ }: memref<?x?xf32, #strided2D>, memref<?x?xf32, #strided2D>, memref<?x?xf32, #strided2D>
return
}
// TILE-2-LABEL: func @pointwise
// TILE-23004-DAG: #[[UB2:.*]] = (d0) -> (d0 + 4)
// TILE-23004-DAG: #[[D0x30pS0x10:.*]] = (d0) -> (d0 * 30)
// TILE-23004-DAG: #[[D0x30pS0x10p90:.*]] = (d0)[s0] -> (d0 * 30 + s0 * 10 + 90)
-func @conv(%arg0: !linalg.view<?x?x?x?xf32>, %arg1: !linalg.view<?x?x?x?xf32>, %arg2: !linalg.view<?x?x?x?xf32>) {
- linalg.conv(%arg0, %arg1, %arg2) {dilations = [10, 20], strides = [30, 40]} : !linalg.view<?x?x?x?xf32>, !linalg.view<?x?x?x?xf32>, !linalg.view<?x?x?x?xf32>
+// TILE-23004-DAG: #[[strided4D:.*]] = (d0, d1, d2, d3)[s0, s1, s2, s3] -> (d0 * s1 + s0 + d1 * s2 + d2 * s3 + d3)
+#strided4D = (d0, d1, d2, d3)[s0, s1, s2, s3] -> (d0 * s1 + s0 + d1 * s2 + d2 * s3 + d3)
+
+func @conv(%arg0: memref<?x?x?x?xf32, #strided4D>, %arg1: memref<?x?x?x?xf32, #strided4D>, %arg2: memref<?x?x?x?xf32, #strided4D>) {
+ linalg.conv(%arg0, %arg1, %arg2) {dilations = [10, 20], strides = [30, 40]} : memref<?x?x?x?xf32, #strided4D>, memref<?x?x?x?xf32, #strided4D>, memref<?x?x?x?xf32, #strided4D>
return
}
-// TILE-23004-LABEL: func @conv(%{{.*}}: !linalg.view<?x?x?x?xf32>, %{{.*}}: !linalg.view<?x?x?x?xf32>, %{{.*}}: !linalg.view<?x?x?x?xf32>) {
-// TILE-23004: %[[Q:.*]] = linalg.dim %{{.*}}, 2 : !linalg.view<?x?x?x?xf32>
-// TILE-23004: %[[B:.*]] = linalg.dim %{{.*}}, 0 : !linalg.view<?x?x?x?xf32>
-// TILE-23004: %[[PaddedInput0:.*]] = linalg.dim %{{.*}}, 1 : !linalg.view<?x?x?x?xf32>
-// TILE-23004: %[[X0:.*]] = linalg.dim %{{.*}}, 1 : !linalg.view<?x?x?x?xf32>
+// TILE-23004-LABEL: func @conv(
+// TILE-23004: %{{.*}}: memref<?x?x?x?xf32, #[[strided4D]]>, %{{.*}}: memref<?x?x?x?xf32, #[[strided4D]]>, %{{.*}}: memref<?x?x?x?xf32, #[[strided4D]]>) {
+// TILE-23004: %[[Q:.*]] = dim %{{.*}}, 2 : memref<?x?x?x?xf32, #[[strided4D]]>
+// TILE-23004: %[[B:.*]] = dim %{{.*}}, 0 : memref<?x?x?x?xf32, #[[strided4D]]>
+// TILE-23004: %[[PaddedInput0:.*]] = dim %{{.*}}, 1 : memref<?x?x?x?xf32, #[[strided4D]]>
+// TILE-23004: %[[X0:.*]] = dim %{{.*}}, 1 : memref<?x?x?x?xf32, #[[strided4D]]>
// TILE-23004: loop.for %{{.*}} = %{{.*}} to %[[B]] step %{{.*}} {
// TILE-23004: loop.for %{{.*}} = %{{.*}} to %[[X0]] step %{{.*}} {
// TILE-23004: loop.for %{{.*}} = %{{.*}} to %[[Q]] step %{{.*}} {
-// TILE-23004: %[[Z0:.*]] = linalg.dim %{{.*}}, 0 : !linalg.view<?x?x?x?xf32>
-// TILE-23004: %[[Z1:.*]] = linalg.dim %{{.*}}, 1 : !linalg.view<?x?x?x?xf32>
+// TILE-23004: %[[Z0:.*]] = dim %{{.*}}, 0 : memref<?x?x?x?xf32, #[[strided4D]]>
+// TILE-23004: %[[Z1:.*]] = dim %{{.*}}, 1 : memref<?x?x?x?xf32, #[[strided4D]]>
// TILE-23004: %[[I2p4:.*]] = affine.apply #[[UB2]](%{{.*}})
-// TILE-23004: %[[K:.*]] = linalg.dim %{{.*}}, 3 : !linalg.view<?x?x?x?xf32>
-// TILE-23004: %[[FilterView:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[Z0]], %{{.*}}, %{{.*}}, %[[Z1]], %{{.*}}, %{{.*}}, %[[I2p4]], %{{.*}}, %{{.*}}, %[[K]], %{{.*}}] : !linalg.view<?x?x?x?xf32>
+// TILE-23004: %[[K:.*]] = dim %{{.*}}, 3 : memref<?x?x?x?xf32, #[[strided4D]]>
+// TILE-23004: %[[FilterView:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[Z0]], %{{.*}}, %{{.*}}, %[[Z1]], %{{.*}}, %{{.*}}, %[[I2p4]], %{{.*}}, %{{.*}}, %[[K]], %{{.*}}] : memref<?x?x?x?xf32, #[[strided4D]]>
//
// TILE-23004: %[[I0p3:.*]] = affine.apply #[[UB0]](%{{.*}})
// TILE-23004: %[[I1:.*]] = affine.apply #[[D0x30pS0x10]](%{{.*}})
// TILE-23004: %[[I1pStep:.*]] = affine.apply #[[D0x30pS0x10p90]](%{{.*}})[%[[PaddedInput0]]]
-// TILE-23004: %[[SZ2:.*]] = linalg.dim %{{.*}}, 2 : !linalg.view<?x?x?x?xf32>
+// TILE-23004: %[[SZ2:.*]] = dim %{{.*}}, 2 : memref<?x?x?x?xf32, #[[strided4D]]>
// TILE-23004: %[[I2p2:.*]] = affine.apply #[[UB2]](%{{.*}})
-// TILE-23004: %[[InputView:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[I0p3]], %{{.*}}, %[[I1]], %[[I1pStep]], %{{.*}}, %{{.*}}, %[[SZ2]], %{{.*}}, %{{.*}}, %[[I2p2]], %{{.*}}] : !linalg.view<?x?x?x?xf32>
+// TILE-23004: %[[InputView:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[I0p3]], %{{.*}}, %[[I1]], %[[I1pStep]], %{{.*}}, %{{.*}}, %[[SZ2]], %{{.*}}, %{{.*}}, %[[I2p2]], %{{.*}}] : memref<?x?x?x?xf32, #[[strided4D]]>
//
// TILE-23004: %[[B:.*]] = affine.apply #[[UB0]](%{{.*}})
// TILE-23004: %[[I1p3:.*]] = affine.apply #[[UB1]](%{{.*}})
-// TILE-23004: %[[X0:.*]] = linalg.dim %{{.*}}, 2 : !linalg.view<?x?x?x?xf32>
-// TILE-23004: %[[X1:.*]] = linalg.dim %{{.*}}, 3 : !linalg.view<?x?x?x?xf32>
-// TILE-23004: %[[OutputView:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[B]], %{{.*}}, %{{.*}}, %[[I1p3]], %{{.*}}, %{{.*}}, %[[X0]], %{{.*}}, %{{.*}}, %[[X1]], %{{.*}}] : !linalg.view<?x?x?x?xf32>
+// TILE-23004: %[[X0:.*]] = dim %{{.*}}, 2 : memref<?x?x?x?xf32, #[[strided4D]]>
+// TILE-23004: %[[X1:.*]] = dim %{{.*}}, 3 : memref<?x?x?x?xf32, #[[strided4D]]>
+// TILE-23004: %[[OutputView:.*]] = linalg.subview %{{.*}}[%{{.*}}, %[[B]], %{{.*}}, %{{.*}}, %[[I1p3]], %{{.*}}, %{{.*}}, %[[X0]], %{{.*}}, %{{.*}}, %[[X1]], %{{.*}}] : memref<?x?x?x?xf32, #[[strided4D]]>
//
-// TILE-23004: linalg.conv(%[[FilterView]], %[[InputView]], %[[OutputView]]) {dilations = [10, 20], strides = [30, 40]} : !linalg.view<?x?x?x?xf32>, !linalg.view<?x?x?x?xf32>, !linalg.view<?x?x?x?xf32>
+// TILE-23004: linalg.conv(%[[FilterView]], %[[InputView]], %[[OutputView]]) {dilations = [10, 20], strides = [30, 40]} : memref<?x?x?x?xf32, #[[strided4D]]>, memref<?x?x?x?xf32, #[[strided4D]]>, memref<?x?x?x?xf32, #[[strided4D]]>
llvm::outs() << "Testing: " << getFunction().getName() << "\n";
getFunction().walk([&](AllocOp allocOp) {
auto memrefType = allocOp.getResult()->getType().cast<MemRefType>();
- SmallVector<int64_t, 4> strideVector;
- if (failed(memrefType.getStridesAndOffset(strideVector))) {
+ int64_t offset;
+ SmallVector<int64_t, 4> strides;
+ if (failed(memrefType.getStridesAndOffset(strides, offset))) {
llvm::outs() << "MemRefType " << memrefType << " cannot be converted to "
<< "strided form\n";
return;
}
- ArrayRef<int64_t> strides(strideVector);
- auto offset = strides.back();
- strides = strides.drop_back();
llvm::outs() << "MemRefType offset: ";
if (offset == MemRefType::kDynamicStrideOrOffset)
llvm::outs() << "?";
unsigned long strides[N];
};
-// This is separated out to avoid `unsigned long sizes[0]` which triggers:
-// warning: ISO C++ forbids zero-size array [-Wpedantic]
template <typename T> struct ViewType<T, 0> {
T *data;
unsigned long offset;
};
extern "C" void linalg_fill_viewf32_f32(ViewType<float, 0> *X, float f) {
- *(X->data + X->offset) = f;
+ X->data[X->offset] = f;
}
-extern "C" void linalg_fill_viewxf32_f32(ViewType<float, 1> *X, float f) {
+extern "C" void linalg_fill_viewsxf32_f32(ViewType<float, 1> *X, float f) {
for (unsigned i = 0; i < X->sizes[0]; ++i)
*(X->data + X->offset + i * X->strides[0]) = f;
}
-extern "C" void linalg_fill_viewxxf32_f32(ViewType<float, 2> *X, float f) {
+extern "C" void linalg_fill_viewsxsxf32_f32(ViewType<float, 2> *X, float f) {
for (unsigned i = 0; i < X->sizes[0]; ++i)
for (unsigned j = 0; j < X->sizes[1]; ++j)
*(X->data + X->offset + i * X->strides[0] + j * X->strides[1]) = f;
O->data[O->offset] = I->data[I->offset];
}
-extern "C" void linalg_copy_viewxf32_viewxf32(ViewType<float, 1> *I,
- ViewType<float, 1> *O) {
+extern "C" void linalg_copy_viewsxf32_viewsxf32(ViewType<float, 1> *I,
+ ViewType<float, 1> *O) {
assert(I->sizes[0] == O->sizes[0]);
for (unsigned i = 0; i < I->sizes[0]; ++i)
O->data[O->offset + i * O->strides[0]] =
I->data[I->offset + i * I->strides[0]];
}
-extern "C" void linalg_copy_viewxxf32_viewxxf32(ViewType<float, 2> *I,
- ViewType<float, 2> *O) {
+extern "C" void linalg_copy_viewsxsxf32_viewsxsxf32(ViewType<float, 2> *I,
+ ViewType<float, 2> *O) {
assert(I->sizes[0] == O->sizes[0]);
assert(I->sizes[1] == O->sizes[1]);
auto so0 = O->strides[0], so1 = O->strides[1];
I->data[I->offset + i * si0 + j * si1];
}
-extern "C" void linalg_dot_viewxf32_viewxf32_viewf32(ViewType<float, 1> *X,
- ViewType<float, 1> *Y,
- ViewType<float, 0> *Z) {
+extern "C" void linalg_dot_viewsxf32_viewsxf32_viewf32(ViewType<float, 1> *X,
+ ViewType<float, 1> *Y,
+ ViewType<float, 0> *Z) {
assert(X->strides[0] == 1);
assert(Y->strides[0] == 1);
assert(X->sizes[0] == Y->sizes[0] && "Expected X and Y of same size");
- *(Z->data + Z->offset) +=
+ Z->data[Z->offset] +=
cblas_sdot(X->sizes[0], X->data + X->offset, X->strides[0],
Y->data + Y->offset, Y->strides[0]);
}
-extern "C" void linalg_matmul_viewxxf32_viewxxf32_viewxxf32(
+extern "C" void linalg_matmul_viewsxsxf32_viewsxsxf32_viewsxsxf32(
ViewType<float, 2> *A, ViewType<float, 2> *B, ViewType<float, 2> *C) {
assert(A->strides[1] == B->strides[1]);
assert(A->strides[1] == C->strides[1]);
-// RUN: mlir-opt %s -linalg-lower-to-llvm-dialect | mlir-cpu-runner -e dot -entry-point-result=f32 -shared-libs=%linalg_test_lib_dir/libcblas%shlibext,%linalg_test_lib_dir/libcblas_interface%shlibext | FileCheck %s
-// RUN: mlir-opt %s -linalg-lower-to-loops -linalg-lower-to-llvm-dialect | mlir-cpu-runner -e dot -entry-point-result=f32 -shared-libs=%linalg_test_lib_dir/libcblas%shlibext,%linalg_test_lib_dir/libcblas_interface%shlibext | FileCheck %s
-// RUN: mlir-opt %s -linalg-lower-to-llvm-dialect | mlir-cpu-runner -e matmul -entry-point-result=f32 -shared-libs=%linalg_test_lib_dir/libcblas%shlibext,%linalg_test_lib_dir/libcblas_interface%shlibext | FileCheck %s
-// RUN: mlir-opt %s -linalg-lower-to-loops -linalg-lower-to-llvm-dialect | mlir-cpu-runner -e matmul -entry-point-result=f32 -shared-libs=%linalg_test_lib_dir/libcblas%shlibext,%linalg_test_lib_dir/libcblas_interface%shlibext | FileCheck %s
-// RUN: mlir-opt %s -linalg-tile -linalg-tile-sizes=2,3,4 -linalg-tile-promote-full-tile-views=true -linalg-lower-to-loops -linalg-lower-to-llvm-dialect | mlir-cpu-runner -e matmul -entry-point-result=f32 -shared-libs=%linalg_test_lib_dir/libcblas%shlibext,%linalg_test_lib_dir/libcblas_interface%shlibext | FileCheck %s
-// RUN: mlir-opt %s -linalg-tile -linalg-tile-sizes=2,3,4 -linalg-tile-promote-full-tile-views=true -linalg-lower-to-llvm-dialect | mlir-cpu-runner -e matmul -entry-point-result=f32 -shared-libs=%linalg_test_lib_dir/libcblas%shlibext,%linalg_test_lib_dir/libcblas_interface%shlibext | FileCheck %s
+// RUN: mlir-opt %s -linalg-convert-to-llvm | mlir-cpu-runner -e dot -entry-point-result=f32 -shared-libs=%linalg_test_lib_dir/libcblas%shlibext,%linalg_test_lib_dir/libcblas_interface%shlibext | FileCheck %s
+// RUN: mlir-opt %s -linalg-lower-to-loops -linalg-convert-to-llvm | mlir-cpu-runner -e dot -entry-point-result=f32 -shared-libs=%linalg_test_lib_dir/libcblas%shlibext,%linalg_test_lib_dir/libcblas_interface%shlibext | FileCheck %s
+// RUN: mlir-opt %s -linalg-convert-to-llvm | mlir-cpu-runner -e matmul -entry-point-result=f32 -shared-libs=%linalg_test_lib_dir/libcblas%shlibext,%linalg_test_lib_dir/libcblas_interface%shlibext | FileCheck %s
+// RUN: mlir-opt %s -linalg-lower-to-loops -linalg-convert-to-llvm | mlir-cpu-runner -e matmul -entry-point-result=f32 -shared-libs=%linalg_test_lib_dir/libcblas%shlibext,%linalg_test_lib_dir/libcblas_interface%shlibext | FileCheck %s
+// RUN: mlir-opt %s -linalg-tile -linalg-tile-sizes=2,3,4 -linalg-tile-promote-full-tile-views=true -linalg-lower-to-loops -linalg-convert-to-llvm | mlir-cpu-runner -e matmul -entry-point-result=f32 -shared-libs=%linalg_test_lib_dir/libcblas%shlibext,%linalg_test_lib_dir/libcblas_interface%shlibext | FileCheck %s
+// RUN: mlir-opt %s -linalg-tile -linalg-tile-sizes=2,3,4 -linalg-tile-promote-full-tile-views=true -linalg-convert-to-llvm | mlir-cpu-runner -e matmul -entry-point-result=f32 -shared-libs=%linalg_test_lib_dir/libcblas%shlibext,%linalg_test_lib_dir/libcblas_interface%shlibext | FileCheck %s
+
+#strided1D = (d0)[s0] -> (d0 + s0)
+#strided2D = (d0, d1)[s0, s1] -> (d0 * s1 + 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) -> !linalg.buffer<?xf32> {
%c1 = constant 1 : index
%buf = linalg.buffer_alloc %s {alignment = 256} : !linalg.buffer<?xf32>
%R = linalg.range %c0:%s:%c1 : !linalg.range
- %V = linalg.view %buf[%R] : !linalg.buffer<?xf32> -> !linalg.view<?xf32>
- linalg.fill(%V, %f) : !linalg.view<?xf32>, f32
+ %V = linalg.view %buf[%R] : !linalg.buffer<?xf32> -> memref<?xf32, #strided1D>
+ linalg.fill(%V, %f) : memref<?xf32, #strided1D>, f32
return %buf : !linalg.buffer<?xf32>
}
%bC = call @alloc_filled_f32(%c1, %f10) : (index, f32) -> (!linalg.buffer<?xf32>)
%R = linalg.range %c0:%c16:%c1 : !linalg.range
- %A = linalg.view %bA[%R] : !linalg.buffer<?xf32> -> !linalg.view<?xf32>
- %B = linalg.view %bB[%R] : !linalg.buffer<?xf32> -> !linalg.view<?xf32>
- %C = linalg.view %bC[] : !linalg.buffer<?xf32> -> !linalg.view<f32>
+ %A = linalg.view %bA[%R] : !linalg.buffer<?xf32> -> memref<?xf32, #strided1D>
+ %B = linalg.view %bB[%R] : !linalg.buffer<?xf32> -> memref<?xf32, #strided1D>
+ %C = linalg.view %bC[] : !linalg.buffer<?xf32> -> memref<f32>
- linalg.dot(%A, %B, %C) : !linalg.view<?xf32>, !linalg.view<?xf32>, !linalg.view<f32>
- %res = linalg.load %C[] : !linalg.view<f32>
+ linalg.dot(%A, %B, %C) : memref<?xf32, #strided1D>, memref<?xf32, #strided1D>, memref<f32>
+ %res = load %C[] : memref<f32>
linalg.buffer_dealloc %bC : !linalg.buffer<?xf32>
linalg.buffer_dealloc %bB : !linalg.buffer<?xf32>
%M = linalg.range %c0:%c10:%c1 : !linalg.range
%N = linalg.range %c0:%c10:%c1 : !linalg.range
%K = linalg.range %c0:%c16:%c1 : !linalg.range
- %A = linalg.view %bA[%M, %K] : !linalg.buffer<?xf32> -> !linalg.view<?x?xf32>
- %B = linalg.view %bB[%K, %N] : !linalg.buffer<?xf32> -> !linalg.view<?x?xf32>
- %C = linalg.view %bC[%M, %N] : !linalg.buffer<?xf32> -> !linalg.view<?x?xf32>
+ %A = linalg.view %bA[%M, %K] : !linalg.buffer<?xf32> -> memref<?x?xf32, #strided2D>
+ %B = linalg.view %bB[%K, %N] : !linalg.buffer<?xf32> -> memref<?x?xf32, #strided2D>
+ %C = linalg.view %bC[%M, %N] : !linalg.buffer<?xf32> -> memref<?x?xf32, #strided2D>
- linalg.matmul(%A, %B, %C) : !linalg.view<?x?xf32>, !linalg.view<?x?xf32>, !linalg.view<?x?xf32>
- %res = linalg.load %C[%c6, %c7] : !linalg.view<?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.buffer_dealloc %bC : !linalg.buffer<?xf32>
linalg.buffer_dealloc %bB : !linalg.buffer<?xf32>