Add a linalg.range_intersect op.

This CL adds an operation whose purpose is to encode boundary conditions directly in the view type. In particular, full/partial tile distinction can
    occur at the level of metadata only.
    This CL also adopts a Linalg_Op pattern that is similar to Std_Op.

--

PiperOrigin-RevId: 248529469
This commit is contained in:
Nicolas Vasilache 2019-05-16 08:15:10 -07:00 committed by Mehdi Amini
parent 090662c5f3
commit a4317d1a59
7 changed files with 164 additions and 84 deletions

View File

@ -19,13 +19,11 @@
//
//===----------------------------------------------------------------------===//
#ifdef LINALG_OPS
#else
#ifdef OP_BASE
#else
include "mlir/IR/OpBase.td"
#endif // OP_BASE
#ifdef LINALG_BASE
#else
#define LINALG_BASE
def Linalg_Dialect : Dialect {
let name = "linalg";
@ -35,8 +33,12 @@ def Linalg_Dialect : Dialect {
def LinalgIsBufferTypePred : CPred<"$_self.isa<BufferType>()">;
def Buffer : Type<LinalgIsBufferTypePred, "buffer">;
// Whether a type is a RangeType.
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_OPS
#endif // LINALG_BASE

View File

@ -20,13 +20,11 @@
//
//===----------------------------------------------------------------------===//
#ifdef LINALG_OPS
#else
#ifdef LINALG_BASE
#else
include "mlir/Linalg/IR/LinalgBase.td"
#endif // LINALG_BASE
#ifdef LINALG_LIBRARY_OPS
#else
#define LINALG_LIBRARY_OPS
class LinalgParametricNativeOpTrait<string prop, string parameters> :
NativeOpTrait<"linalg::" # prop # parameters>
@ -68,7 +66,7 @@ LinalgParametricIntNativeOpTrait<"ViewRanks", ranks>
{}
// Base Tablegen class for Linalg ops.
class LinalgOp<string mnemonic, list<OpTrait> props> :
class LinalgLibrary_Op<string mnemonic, list<OpTrait> props> :
Op<Linalg_Dialect, mnemonic, props> {
let arguments = (ins Variadic<View>); // default variadic builder
let parser = [{ return parseLinalgLibraryOp(parser, result); }];
@ -78,14 +76,14 @@ Op<Linalg_Dialect, mnemonic, props> {
////////////////////////////////////////////////////////////////////////////////
// Concrete Linalg ops.
////////////////////////////////////////////////////////////////////////////////
def DotOp : LinalgOp<"dot", [NInputsAndOutputs<2, 1>,
def DotOp : LinalgLibrary_Op<"dot", [NInputsAndOutputs<2, 1>,
NLoopTypes<0, 1, 0>,
ViewRanks<[1, 1, 0]>]> {}
def MatvecOp : LinalgOp<"matvec", [NInputsAndOutputs<2, 1>,
def MatvecOp : LinalgLibrary_Op<"matvec", [NInputsAndOutputs<2, 1>,
NLoopTypes<1, 1, 0>,
ViewRanks<[2, 1, 1]>]> {}
def MatmulOp : LinalgOp<"matmul", [NInputsAndOutputs<2, 1>,
def MatmulOp : LinalgLibrary_Op<"matmul", [NInputsAndOutputs<2, 1>,
NLoopTypes<2, 1, 0>,
ViewRanks<[2, 2, 2]>]> {}
#endif // LINALG_OPS
#endif // LINALG_LIBRARY_OPS

View File

@ -19,24 +19,42 @@
//
//===----------------------------------------------------------------------===//
include "mlir/Linalg/IR/LinalgBase.td"
#ifdef LINALG_OPS
#else
#define LINALG_OPS
#ifdef LINALG_BASE
#else
include "mlir/Linalg/IR/LinalgBase.td"
#endif // LINALG_BASE
def BufferSizeOp :
Op<Linalg_Dialect, "buffer_size", [NoSideEffect]>,
Arguments<(ins Buffer)>,
Results<(outs Index)>
{
let parser = [{ return parseBufferSizeOp(parser, result); }];
let printer = [{ return printBufferSizeOp(p, *this); }];
// Base class for Linalg dialect ops that do not correspond to library calls.
class Linalg_Op<string mnemonic, list<OpTrait> traits = []> :
Op<Linalg_Dialect, mnemonic, traits> {
// For every linalg op, there needs to be a:
// * void print(OpAsmPrinter *p, ${C++ class of Op} op)
// * LogicalResult verify(${C++ class of Op} op)
// * ParseResult parse${C++ class of Op}(OpAsmParser *parser,
// OperationState *result)
// functions.
let printer = [{ return ::print(p, *this); }];
let verifier = [{ return ::verify(*this); }];
let parser = [{ return ::parse$cppClass(parser, result); }];
}
def DimOp : Op<Linalg_Dialect, "dim", [NoSideEffect]>,
def BufferSizeOp :
Linalg_Op<"buffer_size", [NoSideEffect]>,
Arguments<(ins Buffer)>,
Results<(outs Index)> {
let summary = "buffer size operation";
let description = [{
The "linalg.buffer_size" operation takes a linalg.buffer and returns an
"index". For example:
%0 = linalg.buffer_size %arg0 : !linalg.buffer<f32>
}];
// Fully specified by traits.
let verifier = ?;
}
def DimOp : Linalg_Op<"dim", [NoSideEffect]>,
Arguments<(ins View:$view, APIntAttr:$index)>,
Results<(outs Index)> {
let summary = "dimension index operation";
@ -48,12 +66,14 @@ def DimOp : Op<Linalg_Dialect, "dim", [NoSideEffect]>,
%1 = linalg.dim %0, 2 : view<?x?x?xf32>
}];
let parser = [{ return parseDimOp(parser, result); }];
let printer = [{ return printDimOp(p, *this); }];
let verifier = [{ return ::verify(*this); }];
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",
"Builder *builder, OperationState *result, Value *view, unsigned index",
[{
result->addOperands(view);
result->addAttribute(
@ -65,7 +85,31 @@ def DimOp : Op<Linalg_Dialect, "dim", [NoSideEffect]>,
unsigned getIndex() {
return getAttrOfType<IntegerAttr>("index").getValue().getZExtValue();
}
ViewType getViewType() { return getOperand()->getType().cast<ViewType>(); }
}];
}
def RangeIntersectOp : Linalg_Op<"range_intersect", [NoSideEffect]>,
Arguments<(ins Range, Range)>,
Results<(outs Range)> {
let summary = "range intersection operation";
let description = [{
The "linalg.range_intersect" operation takes two linalg.range and returns a
linalg.range that represents their intersection. This assumes both steps
are one for now. For example:
%2 = linalg.range_intersect %0, %1 : !linalg.range
}];
// Fully verified by traits.
let verifier = ?;
let builders = [OpBuilder<
"Builder *builder, OperationState *result, Value *range1, Value *range2",
[{
result->addOperands({range1, range2});
result->types.push_back(builder->getType<RangeType>());
}]>];
}
#endif // LINALG_OPS

View File

@ -488,12 +488,12 @@ void mlir::linalg::ViewOp::print(OpAsmPrinter *p) {
*p << "] : " << getType();
}
/// Buffer size prints as:
///
/// ``` {.mlir}
/// %0 = linalg.buffer_size %arg0 : !linalg.buffer<f32>
/// ```
static void printBufferSizeOp(OpAsmPrinter *p, BufferSizeOp op) {
///////////////////// 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
// parse`className` function.
static void print(OpAsmPrinter *p, BufferSizeOp op) {
*p << op.getOperationName() << " " << *op.getOperand();
p->printOptionalAttrDict(op.getAttrs());
*p << " : " << op.getOperand()->getType();
@ -511,7 +511,7 @@ static ParseResult parseBufferSizeOp(OpAsmParser *parser,
result->types));
}
static void printDimOp(OpAsmPrinter *p, DimOp op) {
static void print(OpAsmPrinter *p, linalg::DimOp op) {
*p << op.getOperationName() << " " << *op.getOperand() << ", "
<< op.getIndex();
p->printOptionalAttrDict(op.getAttrs(), /*elidedAttrs=*/{"index"});
@ -532,24 +532,29 @@ static ParseResult parseDimOp(OpAsmParser *parser, OperationState *result) {
parser->addTypeToList(indexType, result->types));
}
static LogicalResult verify(linalg::DimOp op) {
// Check that we have an integer index operand.
auto indexAttr = op.getAttrOfType<IntegerAttr>("index");
if (!indexAttr)
return op.emitOpError("requires an integer attribute named 'index'");
uint64_t index = indexAttr.getValue().getZExtValue();
auto type = op.getOperand()->getType();
if (auto viewType = type.dyn_cast<ViewType>()) {
if (index >= viewType.getRank())
return op.emitOpError("index is out of range");
} else {
return op.emitOpError("requires an operand with view type");
}
return success();
static void print(OpAsmPrinter *p, RangeIntersectOp op) {
*p << op.getOperationName() << " " << *op.getOperand(0) << ", "
<< *op.getOperand(1);
p->printOptionalAttrDict(op.getAttrs());
*p << " : " << op.getOperand(0)->getType();
}
static ParseResult parseRangeIntersectOp(OpAsmParser *parser,
OperationState *result) {
SmallVector<OpAsmParser::OperandType, 2> ops;
Type type;
return failure(parser->parseOperandList(ops) ||
parser->parseOptionalAttributeDict(result->attributes) ||
parser->parseColonType(type) ||
parser->resolveOperands(ops, type, result->operands) ||
parser->addTypeToList(type, result->types));
}
/////// Operations corresponding to library calls defined with Tablegen ////////
// For such operations correspond to library calls (i.e. defined in
// LinalgLibraryOps.td), we define an overloaded `print` function and a
// parse`className` function.
// A LinalgLibraryOp prints as:
//
// ```{.mlir}

View File

@ -234,13 +234,13 @@ static SmallVector<Value *, 4> makeTiledViews(FuncBuilder *b, Location loc,
unsigned pos2 = it - nzMap.getResults().begin();
using edsc::op::operator+;
using range = ValueBuilder<RangeOp>;
using range_intersect = ValueBuilder<RangeIntersectOp>;
ScopedContext scope(*b, loc);
ValueHandle iv(ivs[pos2]), step(tileSizes[pos]);
auto min = ValueHandle(extractRangePart(ranges[j], RangePart::Min));
// zero case is important enough to fold away by special-casing.
auto newMin = isZero(min) ? iv : min + iv;
// TODO(ntv): intersect with current range once the operation exists.
Value *r = range(newMin, newMin + step, step);
Value *r = range_intersect(ranges[j], range(newMin, newMin + step, step));
newRanges.push_back(r);
}
res.push_back(createOrReturnView(b, loc, viewDefiningOp, newRanges));

View File

@ -63,3 +63,10 @@ func @dim(%arg0: !linalg.view<?x?xf32>) {
// CHECK-NEXT: %1 = linalg.buffer_alloc %0 : !linalg.buffer<f32>
// CHECK-NEXT: linalg.buffer_dealloc %1 : !linalg.buffer<f32>
func @range_intersect(%arg0: !linalg.range, %arg1: !linalg.range) -> !linalg.range {
%0 = linalg.range_intersect %arg0, %arg1 : !linalg.range
return %0 : !linalg.range
}
// CHECK-LABEL: func @range_intersect(%arg0: !linalg.range, %arg1: !linalg.range) -> !linalg.range {
// CHECK-NEXT: %0 = linalg.range_intersect %arg0, %arg1 : !linalg.range
// CHECK-NEXT: return %0 : !linalg.range

View File

@ -32,10 +32,12 @@ func @matmul(%arg0: !linalg.buffer<f32>, %arg1: index, %arg2: index, %arg3: inde
// TILE-2-NEXT: %[[C:.*]] = linalg.view %arg0[{{.*}}] : !linalg.view<?x?xf32>
// TILE-2: affine.for %i0 = #[[ID]](%c0{{.*}}) to #[[ID]](%arg1) step 2 {
// TILE-2-NEXT: %[[a:.*]] = affine.apply #[[UB0]](%i0)
// TILE-2-NEXT: %[[ra:.*]] = linalg.range %i0:%[[a]]:%c2 : !linalg.range
// TILE-2-NEXT: %[[ra0:.*]] = linalg.range %i0:%[[a]]:%c2 : !linalg.range
// TILE-2-NEXT: %[[ra:.*]] = linalg.range_intersect %{{.}}, %[[ra0]] : !linalg.range
// TILE-2-NEXT: %[[sAi:.*]] = linalg.slice %[[A]][%[[ra]], %2] : !linalg.view<?x?xf32>, !linalg.range, !linalg.range, !linalg.view<?x?xf32>
// TILE-2-NEXT: %[[c:.*]] = affine.apply #[[UB0]](%i0)
// TILE-2-NEXT: %[[rc:.*]] = linalg.range %i0:%[[c]]:%c2 : !linalg.range
// TILE-2-NEXT: %[[rc0:.*]] = linalg.range %i0:%[[c]]:%c2 : !linalg.range
// TILE-2-NEXT: %[[rc:.*]] = linalg.range_intersect %{{.}}, %[[rc0]] : !linalg.range
// TILE-2-NEXT: %[[sCi:.*]] = linalg.slice %[[C]][%[[rc]], %1] : !linalg.view<?x?xf32>, !linalg.range, !linalg.range, !linalg.view<?x?xf32>
// TILE-2-NEXT: linalg.matmul(%[[sAi]], %[[B]], %[[sCi]]) : !linalg.view<?x?xf32>, !linalg.view<?x?xf32>, !linalg.view<?x?xf32>
@ -45,10 +47,12 @@ func @matmul(%arg0: !linalg.buffer<f32>, %arg1: index, %arg2: index, %arg3: inde
// TILE-02-NEXT: %[[C:.*]] = linalg.view %arg0[{{.*}}] : !linalg.view<?x?xf32>
// TILE-02: affine.for %i0 = #[[ID]](%c0_0) to #[[ID]](%arg2) step 2 {
// TILE-02-NEXT: %[[b:.*]] = affine.apply #[[UB0]](%i0)
// TILE-02-NEXT: %[[rb:.*]] = linalg.range %i0:%[[b]]:%c2 : !linalg.range
// TILE-02-NEXT: %[[rb0:.*]] = linalg.range %i0:%[[b]]:%c2 : !linalg.range
// TILE-02-NEXT: %[[rb:.*]] = linalg.range_intersect %{{.}}, %[[rb0]] : !linalg.range
// TILE-02-NEXT: %[[sBj:.*]] = linalg.slice %[[B]][%{{.*}}, %[[rb]]] : !linalg.view<?x?xf32>, !linalg.range, !linalg.range, !linalg.view<?x?xf32>
// TILE-02-NEXT: %[[c:.*]] = affine.apply #[[UB0]](%i0)
// TILE-02-NEXT: %[[rc:.*]] = linalg.range %i0:%[[c]]:%c2 : !linalg.range
// TILE-02-NEXT: %[[rc0:.*]] = linalg.range %i0:%[[c]]:%c2 : !linalg.range
// TILE-02-NEXT: %[[rc:.*]] = linalg.range_intersect %{{.}}, %[[rc0]] : !linalg.range
// TILE-02-NEXT: %[[sCj:.*]] = linalg.slice %[[C]][%{{.*}}, %[[rc]]] : !linalg.view<?x?xf32>, !linalg.range, !linalg.range, !linalg.view<?x?xf32>
// TILE-02-NEXT: linalg.matmul(%[[A]], %[[sBj]], %[[sCj]]) : !linalg.view<?x?xf32>, !linalg.view<?x?xf32>, !linalg.view<?x?xf32>
@ -58,10 +62,12 @@ func @matmul(%arg0: !linalg.buffer<f32>, %arg1: index, %arg2: index, %arg3: inde
// TILE-002-NEXT: %[[C:.*]] = linalg.view %arg0[{{.*}}] : !linalg.view<?x?xf32>
// TILE-002: affine.for %i0 = #[[ID]](%c0{{.*}}) to #[[ID]](%arg3) step 2 {
// TILE-002-NEXT: %[[a:.*]] = affine.apply #[[UB0]](%i0)
// TILE-002-NEXT: %[[ra:.*]] = linalg.range %i0:%[[a]]:%c2 : !linalg.range
// TILE-002-NEXT: %[[ra0:.*]] = linalg.range %i0:%[[a]]:%c2 : !linalg.range
// TILE-002-NEXT: %[[ra:.*]] = linalg.range_intersect %{{.}}, %[[ra0]] : !linalg.range
// TILE-002-NEXT: %[[sAj:.*]] = linalg.slice %[[A]][%{{.*}}, %[[ra]]] : !linalg.view<?x?xf32>, !linalg.range, !linalg.range, !linalg.view<?x?xf32>
// TILE-002-NEXT: %[[b:.*]] = affine.apply #[[UB0]](%i0)
// TILE-002-NEXT: %[[rb:.*]] = linalg.range %i0:%[[b]]:%c2 : !linalg.range
// TILE-002-NEXT: %[[rb0:.*]] = linalg.range %i0:%[[b]]:%c2 : !linalg.range
// TILE-002-NEXT: %[[rb:.*]] = linalg.range_intersect %{{.}}, %[[rb0]] : !linalg.range
// TILE-002-NEXT: %[[sBj:.*]] = linalg.slice %[[B]][%[[rb]], %{{.*}}] : !linalg.view<?x?xf32>, !linalg.range, !linalg.range, !linalg.view<?x?xf32>
// TILE-002-NEXT: linalg.matmul(%[[sAj]], %[[sBj]], %[[C]]) : !linalg.view<?x?xf32>, !linalg.view<?x?xf32>, !linalg.view<?x?xf32>
@ -73,19 +79,25 @@ func @matmul(%arg0: !linalg.buffer<f32>, %arg1: index, %arg2: index, %arg3: inde
// TILE-234-NEXT: affine.for %i1 = #[[ID]](%c0{{.*}}) to #[[ID]](%arg2) step 3 {
// TILE-234-NEXT: affine.for %i2 = #[[ID]](%c0{{.*}}) to #[[ID]](%arg3) step 4 {
// TILE-234-NEXT: %[[ai:.*]] = affine.apply #[[UB0]](%i0)
// TILE-234-NEXT: %[[rai:.*]] = linalg.range %i0:%[[ai]]:%c2{{.*}} : !linalg.range
// TILE-234-NEXT: %[[rai0:.*]] = linalg.range %i0:%[[ai]]:%c2 : !linalg.range
// TILE-234-NEXT: %[[rai:.*]] = linalg.range_intersect %{{.}}, %[[rai0]] : !linalg.range
// TILE-234-NEXT: %[[ak:.*]] = affine.apply #[[UB2]](%i2)
// TILE-234-NEXT: %[[rak:.*]] = linalg.range %i2:%[[ak]]:%c4{{.*}} : !linalg.range
// TILE-234-NEXT: %[[rak0:.*]] = linalg.range %i2:%[[ak]]:%c4{{.*}} : !linalg.range
// TILE-234-NEXT: %[[rak:.*]] = linalg.range_intersect %{{.}}, %[[rak0]] : !linalg.range
// TILE-234-NEXT: %[[sAik:.*]] = linalg.slice %[[A]][%[[rai]], %[[rak]]] : !linalg.view<?x?xf32>, !linalg.range, !linalg.range, !linalg.view<?x?xf32>
// TILE-234-NEXT: %[[bk:.*]] = affine.apply #[[UB2]](%i2)
// TILE-234-NEXT: %[[rbk:.*]] = linalg.range %i2:%[[bk]]:%c4{{.*}} : !linalg.range
// TILE-234-NEXT: %[[rbk0:.*]] = linalg.range %i2:%[[bk]]:%c4{{.*}} : !linalg.range
// TILE-234-NEXT: %[[rbk:.*]] = linalg.range_intersect %{{.}}, %[[rbk0]] : !linalg.range
// TILE-234-NEXT: %[[bj:.*]] = affine.apply #[[UB1]](%i1)
// TILE-234-NEXT: %[[rbj:.*]] = linalg.range %i1:%[[bj]]:%c3{{.*}} : !linalg.range
// TILE-234-NEXT: %[[rbj0:.*]] = linalg.range %i1:%[[bj]]:%c3{{.*}} : !linalg.range
// TILE-234-NEXT: %[[rbj:.*]] = linalg.range_intersect %{{.}}, %[[rbj0]] : !linalg.range
// TILE-234-NEXT: %[[sBkj:.*]] = linalg.slice %[[B]][%[[rbk]], %[[rbj]]] : !linalg.view<?x?xf32>, !linalg.range, !linalg.range, !linalg.view<?x?xf32>
// TILE-234-NEXT: %[[ci:.*]] = affine.apply #[[UB0]](%i0)
// TILE-234-NEXT: %[[rci:.*]] = linalg.range %i0:%[[ci]]:%c2{{.*}} : !linalg.range
// TILE-234-NEXT: %[[rci0:.*]] = linalg.range %i0:%[[ci]]:%c2{{.*}} : !linalg.range
// TILE-234-NEXT: %[[rci:.*]] = linalg.range_intersect %{{.}}, %[[rci0]] : !linalg.range
// TILE-234-NEXT: %[[cj:.*]] = affine.apply #[[UB1]](%i1)
// TILE-234-NEXT: %[[rcj:.*]] = linalg.range %i1:%[[cj]]:%c3{{.*}} : !linalg.range
// TILE-234-NEXT: %[[rcj0:.*]] = linalg.range %i1:%[[cj]]:%c3{{.*}} : !linalg.range
// TILE-234-NEXT: %[[rcj:.*]] = linalg.range_intersect %{{.}}, %[[rcj0]] : !linalg.range
// TILE-234-NEXT: %[[sCij:.*]] = linalg.slice %[[C]][%[[rci]], %[[rcj]]] : !linalg.view<?x?xf32>, !linalg.range, !linalg.range, !linalg.view<?x?xf32>
// TILE-234-NEXT: linalg.matmul(%[[sAik]], %[[sBkj]], %[[sCij]]) : !linalg.view<?x?xf32>, !linalg.view<?x?xf32>, !linalg.view<?x?xf32>
@ -106,10 +118,12 @@ func @matvec(%arg0: !linalg.buffer<f32>, %arg1: index, %arg2: index, %arg3: inde
// TILE-2-NEXT: %[[C:.*]] = linalg.view %arg0[{{.*}}] : !linalg.view<?xf32>
// TILE-2: affine.for %i0 = #[[ID]](%c0{{.*}}) to #[[ID]](%arg1) step 2 {
// TILE-2-NEXT: %[[a:.*]] = affine.apply #[[UB0]](%i0)
// TILE-2-NEXT: %[[ra:.*]] = linalg.range %i0:%[[a]]:%c2 : !linalg.range
// TILE-2-NEXT: %[[ra0:.*]] = linalg.range %i0:%[[a]]:%c2 : !linalg.range
// TILE-2-NEXT: %[[ra:.*]] = linalg.range_intersect %{{.}}, %[[ra0]] : !linalg.range
// TILE-2-NEXT: %[[sAi:.*]] = linalg.slice %[[A]][%[[ra]], %{{.*}}] : !linalg.view<?x?xf32>, !linalg.range, !linalg.range, !linalg.view<?x?xf32>
// TILE-2-NEXT: %[[c:.*]] = affine.apply #[[UB0]](%i0)
// TILE-2-NEXT: %[[rc:.*]] = linalg.range %i0:%[[c]]:%c2 : !linalg.range
// TILE-2-NEXT: %[[rc0:.*]] = linalg.range %i0:%[[c]]:%c2 : !linalg.range
// TILE-2-NEXT: %[[rc:.*]] = linalg.range_intersect %{{.}}, %[[rc0]] : !linalg.range
// TILE-2-NEXT: %[[sCi:.*]] = linalg.slice %[[C]][%[[rc]]] : !linalg.view<?xf32>, !linalg.range, !linalg.view<?xf32>
// TILE-2-NEXT: linalg.matvec(%[[sAi]], %[[B]], %[[sCi]]) : !linalg.view<?x?xf32>, !linalg.view<?xf32>, !linalg.view<?xf32>
@ -119,10 +133,12 @@ func @matvec(%arg0: !linalg.buffer<f32>, %arg1: index, %arg2: index, %arg3: inde
// TILE-02-NEXT: %[[C:.*]] = linalg.view %arg0[{{.*}}] : !linalg.view<?xf32>
// TILE-02: affine.for %i0 = #[[ID]](%c0{{.*}}) to #[[ID]](%arg2) step 2 {
// TILE-02-NEXT: %[[a:.*]] = affine.apply #[[UB0]](%i0)
// TILE-02-NEXT: %[[ra:.*]] = linalg.range %i0:%[[a]]:%c2{{.*}} : !linalg.range
// TILE-02-NEXT: %[[ra0:.*]] = linalg.range %i0:%[[a]]:%c2 : !linalg.range
// TILE-02-NEXT: %[[ra:.*]] = linalg.range_intersect %{{.}}, %[[ra0]] : !linalg.range
// TILE-02-NEXT: %[[sAj:.*]] = linalg.slice %[[A]][%{{.*}}, %[[ra]]] : !linalg.view<?x?xf32>, !linalg.range, !linalg.range, !linalg.view<?x?xf32>
// TILE-02-NEXT: %[[b:.*]] = affine.apply #[[UB0]](%i0)
// TILE-02-NEXT: %[[rb:.*]] = linalg.range %i0:%[[b]]:%c2{{.*}} : !linalg.range
// TILE-02-NEXT: %[[rb0:.*]] = linalg.range %i0:%[[b]]:%c2 : !linalg.range
// TILE-02-NEXT: %[[rb:.*]] = linalg.range_intersect %{{.}}, %[[rb0]] : !linalg.range
// TILE-02-NEXT: %[[sBj:.*]] = linalg.slice %[[B]][%[[rb]]] : !linalg.view<?xf32>, !linalg.range, !linalg.view<?xf32>
// TILE-02-NEXT: linalg.matvec(%[[sAj]], %[[sBj]], %[[C]]) : !linalg.view<?x?xf32>, !linalg.view<?xf32>, !linalg.view<?xf32>
@ -136,15 +152,19 @@ func @matvec(%arg0: !linalg.buffer<f32>, %arg1: index, %arg2: index, %arg3: inde
// TILE-234: affine.for %i0 = #[[ID]](%c0{{.*}}) to #[[ID]](%arg1) step 2 {
// TILE-234-NEXT: affine.for %i1 = #[[ID]](%c0{{.*}}) to #[[ID]](%arg2) step 3 {
// TILE-234-NEXT: %[[ai:.*]] = affine.apply #[[UB0]](%i0)
// TILE-234-NEXT: %[[rai:.*]] = linalg.range %i0:%[[ai]]:%c2 : !linalg.range
// TILE-234-NEXT: %[[rai0:.*]] = linalg.range %i0:%[[ai]]:%c2 : !linalg.range
// TILE-234-NEXT: %[[rai:.*]] = linalg.range_intersect %{{.}}, %[[rai0]] : !linalg.range
// TILE-234-NEXT: %[[aj:.*]] = affine.apply #[[UB1]](%i1)
// TILE-234-NEXT: %[[raj:.*]] = linalg.range %i1:%[[aj]]:%c3 : !linalg.range
// TILE-234-NEXT: %[[raj0:.*]] = linalg.range %i1:%[[aj]]:%c3 : !linalg.range
// TILE-234-NEXT: %[[raj:.*]] = linalg.range_intersect %{{.}}, %[[raj0]] : !linalg.range
// TILE-234-NEXT: %[[sAij:.*]] = linalg.slice %[[A]][%[[rai]], %[[raj]]] : !linalg.view<?x?xf32>, !linalg.range, !linalg.range, !linalg.view<?x?xf32>
// TILE-234-NEXT: %[[b:.*]] = affine.apply #[[UB1]](%i1)
// TILE-234-NEXT: %[[rb:.*]] = linalg.range %i1:%[[b]]:%c3 : !linalg.range
// TILE-234-NEXT: %[[rb0:.*]] = linalg.range %i1:%[[b]]:%c3 : !linalg.range
// TILE-234-NEXT: %[[rb:.*]] = linalg.range_intersect %{{.}}, %[[rb0]] : !linalg.range
// TILE-234-NEXT: %[[sB:.*]] = linalg.slice %[[B]][%[[rb]]] : !linalg.view<?xf32>, !linalg.range, !linalg.view<?xf32>
// TILE-234-NEXT: %[[c:.*]] = affine.apply #[[UB0]](%i0)
// TILE-234-NEXT: %[[rc:.*]] = linalg.range %i0:%[[c]]:%c2 : !linalg.range
// TILE-234-NEXT: %[[rc0:.*]] = linalg.range %i0:%[[c]]:%c2 : !linalg.range
// TILE-234-NEXT: %[[rc:.*]] = linalg.range_intersect %{{.}}, %[[rc0]] : !linalg.range
// TILE-234-NEXT: %[[sC:.*]] = linalg.slice %[[C]][%[[rc]]] : !linalg.view<?xf32>, !linalg.range, !linalg.view<?xf32>
// TILE-234-NEXT: linalg.matvec(%[[sAij]], %[[sB]], %[[sC]]) : !linalg.view<?x?xf32>, !linalg.view<?xf32>, !linalg.view<?xf32>
@ -164,10 +184,12 @@ func @dot(%arg0: !linalg.buffer<f32>, %arg1: index, %arg2: index, %arg3: index)
// TILE-2-NEXT: %[[C:.*]] = linalg.view %arg0[{{.*}}] : !linalg.view<f32>
// TILE-2: affine.for %i0 = #[[ID]](%c0{{.*}}) to #[[ID]](%arg1) step 2 {
// TILE-2-NEXT: %[[a:.*]] = affine.apply #[[UB0]](%i0)
// TILE-2-NEXT: %[[ra:.*]] = linalg.range %i0:%[[a]]:%c2 : !linalg.range
// TILE-2-NEXT: %[[ra0:.*]] = linalg.range %i0:%[[a]]:%c2 : !linalg.range
// TILE-2-NEXT: %[[ra:.*]] = linalg.range_intersect %{{.}}, %[[ra0]] : !linalg.range
// TILE-2-NEXT: %[[sAi:.*]] = linalg.slice %[[A]][%[[ra]]] : !linalg.view<?xf32>, !linalg.range, !linalg.view<?xf32>
// TILE-2-NEXT: %[[b:.*]] = affine.apply #[[UB0]](%i0)
// TILE-2-NEXT: %[[rb:.*]] = linalg.range %i0:%[[b]]:%c2 : !linalg.range
// TILE-2-NEXT: %[[rb0:.*]] = linalg.range %i0:%[[b]]:%c2 : !linalg.range
// TILE-2-NEXT: %[[rb:.*]] = linalg.range_intersect %{{.}}, %[[rb0]] : !linalg.range
// TILE-2-NEXT: %[[sBi:.*]] = linalg.slice %[[B]][%[[rb]]] : !linalg.view<?xf32>, !linalg.range, !linalg.view<?xf32>
// TILE-2-NEXT: linalg.dot(%[[sAi]], %[[sBi]], %[[C]]) : !linalg.view<?xf32>, !linalg.view<?xf32>, !linalg.view<f32>
@ -183,9 +205,11 @@ func @dot(%arg0: !linalg.buffer<f32>, %arg1: index, %arg2: index, %arg3: index)
// TILE-234-NEXT: %[[C:.*]] = linalg.view %arg0[{{.*}}] : !linalg.view<f32>
// TILE-234: affine.for %i0 = #[[ID]](%c0{{.*}}) to #[[ID]](%arg1) step 2 {
// TILE-234-NEXT: %[[a:.*]] = affine.apply #[[UB0]](%i0)
// TILE-234-NEXT: %[[ra:.*]] = linalg.range %i0:%[[a]]:%c2 : !linalg.range
// TILE-234-NEXT: %[[ra0:.*]] = linalg.range %i0:%[[a]]:%c2 : !linalg.range
// TILE-234-NEXT: %[[ra:.*]] = linalg.range_intersect %{{.}}, %[[ra0]] : !linalg.range
// TILE-234-NEXT: %[[sA:.*]] = linalg.slice %[[A]][%[[ra]]] : !linalg.view<?xf32>, !linalg.range, !linalg.view<?xf32>
// TILE-234-NEXT: %[[b:.*]] = affine.apply #[[UB0]](%i0)
// TILE-234-NEXT: %[[rb:.*]] = linalg.range %i0:%[[b]]:%c2 : !linalg.range
// TILE-234-NEXT: %[[rb0:.*]] = linalg.range %i0:%[[b]]:%c2 : !linalg.range
// TILE-234-NEXT: %[[rb:.*]] = linalg.range_intersect %{{.}}, %[[rb0]] : !linalg.range
// TILE-234-NEXT: %[[sB:.*]] = linalg.slice %[[B]][%[[rb]]] : !linalg.view<?xf32>, !linalg.range, !linalg.view<?xf32>
// TILE-234-NEXT: linalg.dot(%[[sA]], %[[sB]], %[[C]]) : !linalg.view<?xf32>, !linalg.view<?xf32>, !linalg.view<f32>