mirror of
https://github.com/intel/llvm.git
synced 2026-01-26 03:56:16 +08:00
[mlir][Vector] Make minor identity permutation map optional in transfer op printing and parsing
Summary: This revision makes the use of vector transfer operatons more idiomatic by allowing to omit and inferring the permutation_map. Differential Revision: https://reviews.llvm.org/D80092
This commit is contained in:
@@ -13,6 +13,7 @@
|
||||
#ifndef MLIR_DIALECT_VECTOR_VECTOROPS_H
|
||||
#define MLIR_DIALECT_VECTOR_VECTOROPS_H
|
||||
|
||||
#include "mlir/IR/AffineMap.h"
|
||||
#include "mlir/IR/Attributes.h"
|
||||
#include "mlir/IR/Dialect.h"
|
||||
#include "mlir/IR/OpDefinition.h"
|
||||
@@ -71,6 +72,14 @@ IntegerType getVectorSubscriptType(Builder &builder);
|
||||
/// the integer type required for subscripts in the vector dialect.
|
||||
ArrayAttr getVectorSubscriptAttr(Builder &b, ArrayRef<int64_t> values);
|
||||
|
||||
namespace impl {
|
||||
/// Build the default minor identity map suitable for a vector transfer. This
|
||||
/// also handles the case memref<... x vector<...>> -> vector<...> in which the
|
||||
/// rank of the identity map must take the vector element type into account.
|
||||
AffineMap getTransferMinorIdentityMap(MemRefType memRefType,
|
||||
VectorType vectorType);
|
||||
} // namespace impl
|
||||
|
||||
#define GET_OP_CLASSES
|
||||
#include "mlir/Dialect/Vector/VectorOps.h.inc"
|
||||
|
||||
|
||||
@@ -863,6 +863,18 @@ def Vector_ExtractStridedSliceOp :
|
||||
let assemblyFormat = "$vector attr-dict `:` type($vector) `to` type(results)";
|
||||
}
|
||||
|
||||
def Vector_TransferOpUtils {
|
||||
code extraTransferDeclaration = [{
|
||||
static StringRef getPermutationMapAttrName() { return "permutation_map"; }
|
||||
MemRefType getMemRefType() {
|
||||
return memref().getType().cast<MemRefType>();
|
||||
}
|
||||
VectorType getVectorType() {
|
||||
return vector().getType().cast<VectorType>();
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
def Vector_TransferReadOp :
|
||||
Vector_Op<"transfer_read">,
|
||||
Arguments<(ins AnyMemRef:$memref, Variadic<Index>:$indices,
|
||||
@@ -884,15 +896,21 @@ def Vector_TransferReadOp :
|
||||
supplied as the operands `2 .. 1 + rank(memref)`. The permutation_map
|
||||
[attribute](../LangRef.md#attributes) is an
|
||||
[affine-map](Affine.md#affine-maps) which specifies the transposition on the
|
||||
slice to match the vector shape. The size of the slice is specified by the
|
||||
size of the vector, given as the return type. An `ssa-value` of the same
|
||||
elemental type as the MemRef is provided as the last operand to specify
|
||||
padding in the case of out-of-bounds accesses. This operation is called
|
||||
'read' by opposition to 'load' because the super-vector granularity is
|
||||
generally not representable with a single hardware register.
|
||||
A `vector.transfer_read` is thus a mid-level
|
||||
abstraction that supports super-vectorization with non-effecting padding for
|
||||
full-tile-only code.
|
||||
slice to match the vector shape. The permutation map may be implicit and
|
||||
ommitted from parsing and printing if it is the canonical minor identity map
|
||||
(i.e. if it does not permute or broadcast any dimension).
|
||||
|
||||
The size of the slice is specified by the size of the vector, given as the
|
||||
return type.
|
||||
|
||||
An `ssa-value` of the same elemental type as the MemRef is provided as the
|
||||
last operand to specify padding in the case of out-of-bounds accesses.
|
||||
|
||||
This operation is called 'read' by opposition to 'load' because the
|
||||
super-vector granularity is generally not representable with a single
|
||||
hardware register. A `vector.transfer_read` is thus a mid-level abstraction
|
||||
that supports super-vectorization with non-effecting padding for full-tile
|
||||
only operations.
|
||||
|
||||
More precisely, let's dive deeper into the permutation_map for the following
|
||||
MLIR:
|
||||
@@ -995,19 +1013,25 @@ def Vector_TransferReadOp :
|
||||
}];
|
||||
|
||||
let builders = [
|
||||
// Builder that sets permutation map and padding to 'getMinorIdentityMap'
|
||||
// and zero, respectively, by default.
|
||||
// Builder that sets padding to zero.
|
||||
OpBuilder<"OpBuilder &builder, OperationState &result, VectorType vector, "
|
||||
"Value memref, ValueRange indices, AffineMap permutationMap">,
|
||||
// Builder that sets permutation map (resp. padding) to
|
||||
// 'getMinorIdentityMap' (resp. zero).
|
||||
OpBuilder<"OpBuilder &builder, OperationState &result, VectorType vector, "
|
||||
"Value memref, ValueRange indices">
|
||||
];
|
||||
|
||||
let extraClassDeclaration = [{
|
||||
MemRefType getMemRefType() {
|
||||
return memref().getType().cast<MemRefType>();
|
||||
}
|
||||
VectorType getVectorType() {
|
||||
return vector().getType().cast<VectorType>();
|
||||
}
|
||||
let extraClassDeclaration = Vector_TransferOpUtils.extraTransferDeclaration #
|
||||
[{
|
||||
/// Build the default minor identity map suitable for a vector transfer.
|
||||
/// This also handles the case memref<... x vector<...>> -> vector<...> in
|
||||
/// which the rank of the identity map must take the vector element type
|
||||
/// into account.
|
||||
static AffineMap getTransferMinorIdentityMap(
|
||||
MemRefType memRefType, VectorType vectorType) {
|
||||
return impl::getTransferMinorIdentityMap(memRefType, vectorType);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
@@ -1033,10 +1057,15 @@ def Vector_TransferWriteOp :
|
||||
supplied as the operands `3 .. 2 + rank(memref)`.
|
||||
The permutation_map [attribute](../LangRef.md#attributes) is an
|
||||
[affine-map](Affine.md#affine-maps) which specifies the transposition on the
|
||||
slice to match the vector shape. The size of the slice is specified by the
|
||||
size of the vector. This operation is called 'write' by opposition to
|
||||
'store' because the super-vector granularity is generally not representable
|
||||
with a single hardware register. A `vector.transfer_write` is thus a
|
||||
slice to match the vector shape. The permutation map may be implicit and
|
||||
ommitted from parsing and printing if it is the canonical minor identity map
|
||||
(i.e. if it does not permute or broadcast any dimension).
|
||||
|
||||
The size of the slice is specified by the size of the vector.
|
||||
|
||||
This operation is called 'write' by opposition to 'store' because the
|
||||
super-vector granularity is generally not representable with a single
|
||||
hardware register. A `vector.transfer_write` is thus a
|
||||
mid-level abstraction that supports super-vectorization with non-effecting
|
||||
padding for full-tile-only code. It is the responsibility of
|
||||
`vector.transfer_write`'s implementation to ensure the memory writes are
|
||||
@@ -1066,23 +1095,21 @@ def Vector_TransferWriteOp :
|
||||
}];
|
||||
|
||||
let builders = [
|
||||
// Builder that sets permutation map and padding to 'getMinorIdentityMap'
|
||||
// by default.
|
||||
// Builder that sets permutation map to 'getMinorIdentityMap'.
|
||||
OpBuilder<"OpBuilder &builder, OperationState &result, Value vector, "
|
||||
"Value memref, ValueRange indices">
|
||||
];
|
||||
|
||||
let extraClassDeclaration = [{
|
||||
VectorType getVectorType() {
|
||||
return vector().getType().cast<VectorType>();
|
||||
}
|
||||
MemRefType getMemRefType() {
|
||||
return memref().getType().cast<MemRefType>();
|
||||
}
|
||||
}];
|
||||
let assemblyFormat = [{
|
||||
$vector `,` $memref `[` $indices `]` attr-dict `:` type($vector) `,`
|
||||
type($memref)
|
||||
let extraClassDeclaration = Vector_TransferOpUtils.extraTransferDeclaration #
|
||||
[{
|
||||
/// Build the default minor identity map suitable for a vector transfer.
|
||||
/// This also handles the case memref<... x vector<...>> -> vector<...> in
|
||||
/// which the rank of the identity map must take the vector element type
|
||||
/// into account.
|
||||
static AffineMap getTransferMinorIdentityMap(
|
||||
MemRefType memRefType, VectorType vectorType) {
|
||||
return impl::getTransferMinorIdentityMap(memRefType, vectorType);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
|
||||
@@ -187,15 +187,15 @@ LogicalResult NDTransferOpHelper<TransferReadOp>::doReplace() {
|
||||
MemRefBoundsCapture &memrefBounds) {
|
||||
// If in-bounds, index into memref and lower to 1-D transfer read.
|
||||
auto thenBlockBuilder = [&](ValueRange majorIvsPlusOffsets) {
|
||||
auto map = AffineMap::getMinorIdentityMap(
|
||||
xferOp.getMemRefType().getRank(), minorRank, xferOp.getContext());
|
||||
// Lower to 1-D vector_transfer_read and let recursion handle it.
|
||||
Value memref = xferOp.memref();
|
||||
SmallVector<Value, 8> indexing;
|
||||
indexing.reserve(leadingRank + majorRank + minorRank);
|
||||
indexing.append(leadingOffsets.begin(), leadingOffsets.end());
|
||||
indexing.append(majorIvsPlusOffsets.begin(), majorIvsPlusOffsets.end());
|
||||
indexing.append(minorOffsets.begin(), minorOffsets.end());
|
||||
// Lower to 1-D vector_transfer_read and let recursion handle it.
|
||||
Value memref = xferOp.memref();
|
||||
auto map = TransferReadOp::getTransferMinorIdentityMap(
|
||||
xferOp.getMemRefType(), minorVectorType);
|
||||
auto loaded1D =
|
||||
vector_transfer_read(minorVectorType, memref, indexing,
|
||||
AffineMapAttr::get(map), xferOp.padding());
|
||||
@@ -230,14 +230,15 @@ LogicalResult NDTransferOpHelper<TransferWriteOp>::doReplace() {
|
||||
MemRefBoundsCapture &memrefBounds) {
|
||||
auto thenBlockBuilder = [&](ValueRange majorIvsPlusOffsets) {
|
||||
// Lower to 1-D vector_transfer_write and let recursion handle it.
|
||||
Value loaded1D = std_load(alloc, majorIvs);
|
||||
auto map = AffineMap::getMinorIdentityMap(
|
||||
xferOp.getMemRefType().getRank(), minorRank, xferOp.getContext());
|
||||
SmallVector<Value, 8> indexing;
|
||||
indexing.reserve(leadingRank + majorRank + minorRank);
|
||||
indexing.append(leadingOffsets.begin(), leadingOffsets.end());
|
||||
indexing.append(majorIvsPlusOffsets.begin(), majorIvsPlusOffsets.end());
|
||||
indexing.append(minorOffsets.begin(), minorOffsets.end());
|
||||
// Lower to 1-D vector_transfer_write and let recursion handle it.
|
||||
Value loaded1D = std_load(alloc, majorIvs);
|
||||
auto map = TransferWriteOp::getTransferMinorIdentityMap(
|
||||
xferOp.getMemRefType(), minorVectorType);
|
||||
vector_transfer_write(loaded1D, xferOp.memref(), indexing,
|
||||
AffineMapAttr::get(map));
|
||||
};
|
||||
|
||||
@@ -793,10 +793,7 @@ static LogicalResult vectorizeRootOrTerminal(Value iv,
|
||||
LLVM_DEBUG(permutationMap.print(dbgs()));
|
||||
auto transfer = b.create<vector::TransferReadOp>(
|
||||
opInst->getLoc(), vectorType, memoryOp.getMemRef(), indices,
|
||||
AffineMapAttr::get(permutationMap),
|
||||
// TODO(b/144455320) add a proper padding value, not just 0.0 : f32
|
||||
state->folder->create<ConstantFloatOp>(b, opInst->getLoc(),
|
||||
APFloat(0.0f), b.getF32Type()));
|
||||
permutationMap);
|
||||
state->registerReplacement(opInst, transfer.getOperation());
|
||||
} else {
|
||||
state->registerTerminal(opInst);
|
||||
|
||||
@@ -1281,28 +1281,60 @@ static LogicalResult verifyTransferOp(Operation *op, MemRefType memrefType,
|
||||
if (permutationMap.getNumInputs() != memrefType.getRank())
|
||||
return op->emitOpError("requires a permutation_map with input dims of the "
|
||||
"same rank as the memref type");
|
||||
|
||||
return success();
|
||||
}
|
||||
|
||||
/// Build the default minor identity map suitable for a vector transfer. This
|
||||
/// also handles the case memref<... x vector<...>> -> vector<...> in which the
|
||||
/// rank of the identity map must take the vector element type into account.
|
||||
AffineMap
|
||||
mlir::vector::impl::getTransferMinorIdentityMap(MemRefType memRefType,
|
||||
VectorType vectorType) {
|
||||
int64_t elementVectorRank = 0;
|
||||
VectorType elementVectorType =
|
||||
memRefType.getElementType().dyn_cast<VectorType>();
|
||||
if (elementVectorType)
|
||||
elementVectorRank += elementVectorType.getRank();
|
||||
return AffineMap::getMinorIdentityMap(
|
||||
memRefType.getRank(), vectorType.getRank() - elementVectorRank,
|
||||
memRefType.getContext());
|
||||
}
|
||||
|
||||
/// Builder that sets permutation map and padding to 'getMinorIdentityMap' and
|
||||
/// zero, respectively, by default.
|
||||
void TransferReadOp::build(OpBuilder &builder, OperationState &result,
|
||||
VectorType vector, Value memref,
|
||||
ValueRange indices) {
|
||||
auto permMap = AffineMap::getMinorIdentityMap(
|
||||
memref.getType().cast<MemRefType>().getRank(), vector.getRank(),
|
||||
builder.getContext());
|
||||
VectorType vector, Value memref, ValueRange indices,
|
||||
AffineMap permutationMap) {
|
||||
Type elemType = vector.cast<VectorType>().getElementType();
|
||||
Value padding = builder.create<ConstantOp>(result.location, elemType,
|
||||
builder.getZeroAttr(elemType));
|
||||
build(builder, result, vector, memref, indices, permutationMap, padding);
|
||||
}
|
||||
|
||||
build(builder, result, vector, memref, indices, permMap, padding);
|
||||
/// Builder that sets permutation map (resp. padding) to 'getMinorIdentityMap'
|
||||
/// (resp. zero).
|
||||
void TransferReadOp::build(OpBuilder &builder, OperationState &result,
|
||||
VectorType vectorType, Value memref,
|
||||
ValueRange indices) {
|
||||
build(builder, result, vectorType, memref, indices,
|
||||
getTransferMinorIdentityMap(memref.getType().cast<MemRefType>(),
|
||||
vectorType));
|
||||
}
|
||||
|
||||
template <typename TransferOp>
|
||||
void printTransferAttrs(OpAsmPrinter &p, TransferOp op) {
|
||||
SmallVector<StringRef, 1> elidedAttrs;
|
||||
if (op.permutation_map() == TransferOp::getTransferMinorIdentityMap(
|
||||
op.getMemRefType(), op.getVectorType()))
|
||||
elidedAttrs.push_back(op.getPermutationMapAttrName());
|
||||
p.printOptionalAttrDict(op.getAttrs(), elidedAttrs);
|
||||
}
|
||||
|
||||
static void print(OpAsmPrinter &p, TransferReadOp op) {
|
||||
p << op.getOperationName() << " " << op.memref() << "[" << op.indices()
|
||||
<< "], " << op.padding() << " ";
|
||||
p.printOptionalAttrDict(op.getAttrs());
|
||||
<< "], " << op.padding();
|
||||
printTransferAttrs(p, op);
|
||||
p << " : " << op.getMemRefType() << ", " << op.getVectorType();
|
||||
}
|
||||
|
||||
@@ -1313,7 +1345,7 @@ static ParseResult parseTransferReadOp(OpAsmParser &parser,
|
||||
SmallVector<OpAsmParser::OperandType, 8> indexInfo;
|
||||
OpAsmParser::OperandType paddingInfo;
|
||||
SmallVector<Type, 2> types;
|
||||
// Parsing with support for optional paddingValue.
|
||||
// Parsing with support for paddingValue.
|
||||
if (parser.parseOperand(memrefInfo) ||
|
||||
parser.parseOperandList(indexInfo, OpAsmParser::Delimiter::Square) ||
|
||||
parser.parseComma() || parser.parseOperand(paddingInfo) ||
|
||||
@@ -1321,12 +1353,21 @@ static ParseResult parseTransferReadOp(OpAsmParser &parser,
|
||||
parser.getCurrentLocation(&typesLoc) || parser.parseColonTypeList(types))
|
||||
return failure();
|
||||
if (types.size() != 2)
|
||||
return parser.emitError(typesLoc, "two types required");
|
||||
return parser.emitError(typesLoc, "requires two types");
|
||||
auto indexType = parser.getBuilder().getIndexType();
|
||||
MemRefType memRefType = types[0].dyn_cast<MemRefType>();
|
||||
if (!memRefType)
|
||||
return parser.emitError(typesLoc, "memref type required"), failure();
|
||||
Type vectorType = types[1];
|
||||
return parser.emitError(typesLoc, "requires memref type");
|
||||
VectorType vectorType = types[1].dyn_cast<VectorType>();
|
||||
if (!vectorType)
|
||||
return parser.emitError(typesLoc, "requires vector type");
|
||||
auto permutationAttrName = TransferReadOp::getPermutationMapAttrName();
|
||||
auto attr = result.attributes.get(permutationAttrName);
|
||||
if (!attr) {
|
||||
auto permMap =
|
||||
TransferReadOp::getTransferMinorIdentityMap(memRefType, vectorType);
|
||||
result.attributes.set(permutationAttrName, AffineMapAttr::get(permMap));
|
||||
}
|
||||
return failure(
|
||||
parser.resolveOperand(memrefInfo, memRefType, result.operands) ||
|
||||
parser.resolveOperands(indexInfo, indexType, result.operands) ||
|
||||
@@ -1376,17 +1417,56 @@ static LogicalResult verify(TransferReadOp op) {
|
||||
// TransferWriteOp
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// Builder that sets permutation map and padding to 'getMinorIdentityMap' by
|
||||
/// default.
|
||||
/// Builder that sets permutation map to 'getMinorIdentityMap'.
|
||||
void TransferWriteOp::build(OpBuilder &builder, OperationState &result,
|
||||
Value vector, Value memref, ValueRange indices) {
|
||||
auto vectorType = vector.getType().cast<VectorType>();
|
||||
auto permMap = AffineMap::getMinorIdentityMap(
|
||||
memref.getType().cast<MemRefType>().getRank(), vectorType.getRank(),
|
||||
builder.getContext());
|
||||
auto permMap = getTransferMinorIdentityMap(
|
||||
memref.getType().cast<MemRefType>(), vectorType);
|
||||
build(builder, result, vector, memref, indices, permMap);
|
||||
}
|
||||
|
||||
static ParseResult parseTransferWriteOp(OpAsmParser &parser,
|
||||
OperationState &result) {
|
||||
llvm::SMLoc typesLoc;
|
||||
OpAsmParser::OperandType vectorInfo, memrefInfo;
|
||||
SmallVector<OpAsmParser::OperandType, 8> indexInfo;
|
||||
SmallVector<Type, 2> types;
|
||||
if (parser.parseOperand(vectorInfo) || parser.parseComma() ||
|
||||
parser.parseOperand(memrefInfo) ||
|
||||
parser.parseOperandList(indexInfo, OpAsmParser::Delimiter::Square) ||
|
||||
parser.parseOptionalAttrDict(result.attributes) ||
|
||||
parser.getCurrentLocation(&typesLoc) || parser.parseColonTypeList(types))
|
||||
return failure();
|
||||
if (types.size() != 2)
|
||||
return parser.emitError(typesLoc, "requires two types");
|
||||
auto indexType = parser.getBuilder().getIndexType();
|
||||
VectorType vectorType = types[0].dyn_cast<VectorType>();
|
||||
if (!vectorType)
|
||||
return parser.emitError(typesLoc, "requires vector type");
|
||||
MemRefType memRefType = types[1].dyn_cast<MemRefType>();
|
||||
if (!memRefType)
|
||||
return parser.emitError(typesLoc, "requires memref type");
|
||||
auto permutationAttrName = TransferWriteOp::getPermutationMapAttrName();
|
||||
auto attr = result.attributes.get(permutationAttrName);
|
||||
if (!attr) {
|
||||
auto permMap =
|
||||
TransferWriteOp::getTransferMinorIdentityMap(memRefType, vectorType);
|
||||
result.attributes.set(permutationAttrName, AffineMapAttr::get(permMap));
|
||||
}
|
||||
return failure(
|
||||
parser.resolveOperand(vectorInfo, vectorType, result.operands) ||
|
||||
parser.resolveOperand(memrefInfo, memRefType, result.operands) ||
|
||||
parser.resolveOperands(indexInfo, indexType, result.operands));
|
||||
}
|
||||
|
||||
static void print(OpAsmPrinter &p, TransferWriteOp op) {
|
||||
p << op.getOperationName() << " " << op.vector() << ", " << op.memref() << "["
|
||||
<< op.indices() << "]";
|
||||
printTransferAttrs(p, op);
|
||||
p << " : " << op.getVectorType() << ", " << op.getMemRefType();
|
||||
}
|
||||
|
||||
static LogicalResult verify(TransferWriteOp op) {
|
||||
// Consistency of elemental types in memref and vector.
|
||||
MemRefType memrefType = op.getMemRefType();
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
// RUN: mlir-opt -lower-affine --split-input-file %s | FileCheck %s
|
||||
|
||||
// CHECK: #[[perm_map:.*]] = affine_map<(d0) -> (d0)>
|
||||
// CHECK-LABEL: func @affine_vector_load
|
||||
func @affine_vector_load(%arg0 : index) {
|
||||
%0 = alloc() : memref<100xf32>
|
||||
@@ -12,13 +11,12 @@ func @affine_vector_load(%arg0 : index) {
|
||||
// CHECK-NEXT: %[[c7:.*]] = constant 7 : index
|
||||
// CHECK-NEXT: %[[b:.*]] = addi %[[a]], %[[c7]] : index
|
||||
// CHECK-NEXT: %[[pad:.*]] = constant 0.0
|
||||
// CHECK-NEXT: vector.transfer_read %[[buf]][%[[b]]], %[[pad]] {permutation_map = #[[perm_map]]} : memref<100xf32>, vector<8xf32>
|
||||
// CHECK-NEXT: vector.transfer_read %[[buf]][%[[b]]], %[[pad]] : memref<100xf32>, vector<8xf32>
|
||||
return
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
// CHECK: #[[perm_map:.*]] = affine_map<(d0) -> (d0)>
|
||||
// CHECK-LABEL: func @affine_vector_store
|
||||
func @affine_vector_store(%arg0 : index) {
|
||||
%0 = alloc() : memref<100xf32>
|
||||
@@ -33,13 +31,12 @@ func @affine_vector_store(%arg0 : index) {
|
||||
// CHECK-NEXT: %[[b:.*]] = addi %{{.*}}, %[[a]] : index
|
||||
// CHECK-NEXT: %[[c7:.*]] = constant 7 : index
|
||||
// CHECK-NEXT: %[[c:.*]] = addi %[[b]], %[[c7]] : index
|
||||
// CHECK-NEXT: vector.transfer_write %[[val]], %[[buf]][%[[c]]] {permutation_map = #[[perm_map]]} : vector<4xf32>, memref<100xf32>
|
||||
// CHECK-NEXT: vector.transfer_write %[[val]], %[[buf]][%[[c]]] : vector<4xf32>, memref<100xf32>
|
||||
return
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
// CHECK: #[[perm_map:.*]] = affine_map<(d0) -> (d0)>
|
||||
// CHECK-LABEL: func @affine_vector_load
|
||||
func @affine_vector_load(%arg0 : index) {
|
||||
%0 = alloc() : memref<100xf32>
|
||||
@@ -51,13 +48,12 @@ func @affine_vector_load(%arg0 : index) {
|
||||
// CHECK-NEXT: %[[c7:.*]] = constant 7 : index
|
||||
// CHECK-NEXT: %[[b:.*]] = addi %[[a]], %[[c7]] : index
|
||||
// CHECK-NEXT: %[[pad:.*]] = constant 0.0
|
||||
// CHECK-NEXT: vector.transfer_read %[[buf]][%[[b]]], %[[pad]] {permutation_map = #[[perm_map]]} : memref<100xf32>, vector<8xf32>
|
||||
// CHECK-NEXT: vector.transfer_read %[[buf]][%[[b]]], %[[pad]] : memref<100xf32>, vector<8xf32>
|
||||
return
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
// CHECK: #[[perm_map:.*]] = affine_map<(d0) -> (d0)>
|
||||
// CHECK-LABEL: func @affine_vector_store
|
||||
func @affine_vector_store(%arg0 : index) {
|
||||
%0 = alloc() : memref<100xf32>
|
||||
@@ -72,13 +68,12 @@ func @affine_vector_store(%arg0 : index) {
|
||||
// CHECK-NEXT: %[[b:.*]] = addi %{{.*}}, %[[a]] : index
|
||||
// CHECK-NEXT: %[[c7:.*]] = constant 7 : index
|
||||
// CHECK-NEXT: %[[c:.*]] = addi %[[b]], %[[c7]] : index
|
||||
// CHECK-NEXT: vector.transfer_write %[[val]], %[[buf]][%[[c]]] {permutation_map = #[[perm_map]]} : vector<4xf32>, memref<100xf32>
|
||||
// CHECK-NEXT: vector.transfer_write %[[val]], %[[buf]][%[[c]]] : vector<4xf32>, memref<100xf32>
|
||||
return
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
// CHECK: #[[perm_map:.*]] = affine_map<(d0, d1) -> (d0, d1)>
|
||||
// CHECK-LABEL: func @vector_load_2d
|
||||
func @vector_load_2d() {
|
||||
%0 = alloc() : memref<100x100xf32>
|
||||
@@ -89,7 +84,7 @@ func @vector_load_2d() {
|
||||
// CHECK: scf.for %[[i0:.*]] =
|
||||
// CHECK: scf.for %[[i1:.*]] =
|
||||
// CHECK-NEXT: %[[pad:.*]] = constant 0.0
|
||||
// CHECK-NEXT: vector.transfer_read %[[buf]][%[[i0]], %[[i1]]], %[[pad]] {permutation_map = #[[perm_map]]} : memref<100x100xf32>, vector<2x8xf32>
|
||||
// CHECK-NEXT: vector.transfer_read %[[buf]][%[[i0]], %[[i1]]], %[[pad]] : memref<100x100xf32>, vector<2x8xf32>
|
||||
}
|
||||
}
|
||||
return
|
||||
@@ -97,7 +92,6 @@ func @vector_load_2d() {
|
||||
|
||||
// -----
|
||||
|
||||
// CHECK: #[[perm_map:.*]] = affine_map<(d0, d1) -> (d0, d1)>
|
||||
// CHECK-LABEL: func @vector_store_2d
|
||||
func @vector_store_2d() {
|
||||
%0 = alloc() : memref<100x100xf32>
|
||||
@@ -109,7 +103,7 @@ func @vector_store_2d() {
|
||||
// CHECK: %[[val:.*]] = constant dense
|
||||
// CHECK: scf.for %[[i0:.*]] =
|
||||
// CHECK: scf.for %[[i1:.*]] =
|
||||
// CHECK-NEXT: vector.transfer_write %[[val]], %[[buf]][%[[i0]], %[[i1]]] {permutation_map = #[[perm_map]]} : vector<2x8xf32>, memref<100x100xf32>
|
||||
// CHECK-NEXT: vector.transfer_write %[[val]], %[[buf]][%[[i0]], %[[i1]]] : vector<2x8xf32>, memref<100x100xf32>
|
||||
}
|
||||
}
|
||||
return
|
||||
|
||||
@@ -229,7 +229,7 @@ func @transfer_read_progressive(%A : memref<?x?xf32>, %base: index) -> vector<17
|
||||
// CHECK: %[[cmp:.*]] = cmpi "slt", %[[add]], %[[dim]] : index
|
||||
// CHECK: %[[cond1:.*]] = and %[[cmp]], %[[cond0]] : i1
|
||||
// CHECK: scf.if %[[cond1]] {
|
||||
// CHECK: %[[vec_1d:.*]] = vector.transfer_read %[[A]][%[[add]], %[[base]]], %[[cst]] {permutation_map = #[[MAP1]]} : memref<?x?xf32>, vector<15xf32>
|
||||
// CHECK: %[[vec_1d:.*]] = vector.transfer_read %[[A]][%[[add]], %[[base]]], %[[cst]] : memref<?x?xf32>, vector<15xf32>
|
||||
// CHECK: store %[[vec_1d]], %[[alloc]][%[[I]]] : memref<17xvector<15xf32>>
|
||||
// CHECK: } else {
|
||||
// CHECK: store %[[splat]], %[[alloc]][%[[I]]] : memref<17xvector<15xf32>>
|
||||
@@ -264,7 +264,7 @@ func @transfer_write_progressive(%A : memref<?x?xf32>, %base: index, %vec: vecto
|
||||
// CHECK: %[[cond1:.*]] = and %[[cmp]], %[[cond0]] : i1
|
||||
// CHECK: scf.if %[[cond1]] {
|
||||
// CHECK: %[[vec_1d:.*]] = load %0[%[[I]]] : memref<17xvector<15xf32>>
|
||||
// CHECK: vector.transfer_write %[[vec_1d]], %[[A]][%[[add]], %[[base]]] {permutation_map = #[[MAP1]]} : vector<15xf32>, memref<?x?xf32>
|
||||
// CHECK: vector.transfer_write %[[vec_1d]], %[[A]][%[[add]], %[[base]]] : vector<15xf32>, memref<?x?xf32>
|
||||
// CHECK: }
|
||||
vector.transfer_write %vec, %A[%base, %base]
|
||||
{permutation_map = affine_map<(d0, d1) -> (d0, d1)>} :
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
// Permutation maps used in vectorization.
|
||||
// CHECK: #[[map_proj_d0d1_0:map[0-9]+]] = affine_map<(d0, d1) -> (0)>
|
||||
// CHECK: #[[map_proj_d0d1_d1:map[0-9]+]] = affine_map<(d0, d1) -> (d1)>
|
||||
|
||||
#map0 = affine_map<(d0) -> (d0)>
|
||||
#mapadd1 = affine_map<(d0) -> (d0 + 1)>
|
||||
@@ -13,7 +12,6 @@
|
||||
// Maps introduced to vectorize fastest varying memory index.
|
||||
// CHECK-LABEL: func @vec1d_1
|
||||
func @vec1d_1(%A : memref<?x?xf32>, %B : memref<?x?x?xf32>) {
|
||||
// CHECK-DAG: %{{.*}} = constant 0.0{{.*}}: f32
|
||||
// CHECK-DAG: %[[C0:[a-z0-9_]+]] = constant 0 : index
|
||||
// CHECK-DAG: [[ARG_M:%[0-9]+]] = dim %{{.*}}, 0 : memref<?x?xf32>
|
||||
// CHECK-DAG: [[ARG_N:%[0-9]+]] = dim %{{.*}}, 1 : memref<?x?xf32>
|
||||
@@ -22,10 +20,11 @@ func @vec1d_1(%A : memref<?x?xf32>, %B : memref<?x?x?xf32>) {
|
||||
%N = dim %A, 1 : memref<?x?xf32>
|
||||
%P = dim %B, 2 : memref<?x?x?xf32>
|
||||
%cst0 = constant 0 : index
|
||||
//
|
||||
|
||||
// CHECK: for {{.*}} step 128
|
||||
// CHECK-NEXT: %{{.*}} = affine.apply #map0(%[[C0]])
|
||||
// CHECK-NEXT: %{{.*}} = affine.apply #map0(%[[C0]])
|
||||
// CHECK-NEXT: %{{.*}} = constant 0.0{{.*}}: f32
|
||||
// CHECK-NEXT: {{.*}} = vector.transfer_read %{{.*}}[%{{.*}}, %{{.*}}], %{{.*}} {permutation_map = #[[map_proj_d0d1_0]]} : memref<?x?xf32>, vector<128xf32>
|
||||
affine.for %i0 = 0 to %M { // vectorized due to scalar -> vector
|
||||
%a0 = affine.load %A[%cst0, %cst0] : memref<?x?xf32>
|
||||
@@ -35,7 +34,6 @@ func @vec1d_1(%A : memref<?x?xf32>, %B : memref<?x?x?xf32>) {
|
||||
|
||||
// CHECK-LABEL: func @vec1d_2
|
||||
func @vec1d_2(%A : memref<?x?xf32>, %B : memref<?x?x?xf32>) {
|
||||
// CHECK-DAG: %{{.*}} = constant 0.0{{.*}}: f32
|
||||
// CHECK-DAG: %[[C0:[a-z0-9_]+]] = constant 0 : index
|
||||
// CHECK-DAG: [[ARG_M:%[0-9]+]] = dim %{{.*}}, 0 : memref<?x?xf32>
|
||||
// CHECK-DAG: [[ARG_N:%[0-9]+]] = dim %{{.*}}, 1 : memref<?x?xf32>
|
||||
@@ -46,7 +44,8 @@ func @vec1d_2(%A : memref<?x?xf32>, %B : memref<?x?x?xf32>) {
|
||||
%cst0 = constant 0 : index
|
||||
//
|
||||
// CHECK:for [[IV3:%[a-zA-Z0-9]+]] = 0 to [[ARG_M]] step 128
|
||||
// CHECK-NEXT: {{.*}} = vector.transfer_read %{{.*}}[%{{.*}}, %{{.*}}], %{{.*}} {permutation_map = #[[map_proj_d0d1_d1]]} : memref<?x?xf32>, vector<128xf32>
|
||||
// CHECK-NEXT: %[[CST:.*]] = constant 0.0{{.*}}: f32
|
||||
// CHECK-NEXT: {{.*}} = vector.transfer_read %{{.*}}[%{{.*}}, %{{.*}}], %[[CST]] : memref<?x?xf32>, vector<128xf32>
|
||||
affine.for %i3 = 0 to %M { // vectorized
|
||||
%a3 = affine.load %A[%cst0, %i3] : memref<?x?xf32>
|
||||
}
|
||||
@@ -55,7 +54,6 @@ func @vec1d_2(%A : memref<?x?xf32>, %B : memref<?x?x?xf32>) {
|
||||
|
||||
// CHECK-LABEL: func @vec1d_3
|
||||
func @vec1d_3(%A : memref<?x?xf32>, %B : memref<?x?x?xf32>) {
|
||||
// CHECK-DAG: %{{.*}} = constant 0.0{{.*}}: f32
|
||||
// CHECK-DAG: %[[C0:[a-z0-9_]+]] = constant 0 : index
|
||||
// CHECK-DAG: [[ARG_M:%[0-9]+]] = dim %arg0, 0 : memref<?x?xf32>
|
||||
// CHECK-DAG: [[ARG_N:%[0-9]+]] = dim %arg0, 1 : memref<?x?xf32>
|
||||
@@ -69,7 +67,8 @@ func @vec1d_3(%A : memref<?x?xf32>, %B : memref<?x?x?xf32>) {
|
||||
// CHECK-NEXT: for [[IV9:%[arg0-9]*]] = 0 to [[ARG_N]] {
|
||||
// CHECK-NEXT: %[[APP9_0:[0-9]+]] = affine.apply {{.*}}([[IV9]], [[IV8]])
|
||||
// CHECK-NEXT: %[[APP9_1:[0-9]+]] = affine.apply {{.*}}([[IV9]], [[IV8]])
|
||||
// CHECK-NEXT: {{.*}} = vector.transfer_read %{{.*}}[%[[APP9_0]], %[[APP9_1]]], %{{.*}} {permutation_map = #[[map_proj_d0d1_d1]]} : memref<?x?xf32>, vector<128xf32>
|
||||
// CHECK-NEXT: %[[CST:.*]] = constant 0.0{{.*}}: f32
|
||||
// CHECK-NEXT: {{.*}} = vector.transfer_read %{{.*}}[%[[APP9_0]], %[[APP9_1]]], %[[CST]] : memref<?x?xf32>, vector<128xf32>
|
||||
affine.for %i8 = 0 to %M { // vectorized
|
||||
affine.for %i9 = 0 to %N {
|
||||
%a9 = affine.load %A[%i9, %i8 + %i9] : memref<?x?xf32>
|
||||
@@ -87,31 +86,31 @@ func @vector_add_2d(%M : index, %N : index) -> f32 {
|
||||
%f2 = constant 2.0 : f32
|
||||
affine.for %i0 = 0 to %M {
|
||||
affine.for %i1 = 0 to %N {
|
||||
// CHECK: [[C1:%.*]] = constant dense<1.000000e+00> : vector<128xf32>
|
||||
// CHECK: vector.transfer_write [[C1]], {{.*}} {permutation_map = #[[map_proj_d0d1_d1]]} : vector<128xf32>, memref<?x?xf32>
|
||||
// CHECK: %[[C1:.*]] = constant dense<1.000000e+00> : vector<128xf32>
|
||||
// CHECK: vector.transfer_write %[[C1]], {{.*}} : vector<128xf32>, memref<?x?xf32>
|
||||
// non-scoped %f1
|
||||
affine.store %f1, %A[%i0, %i1] : memref<?x?xf32, 0>
|
||||
}
|
||||
}
|
||||
affine.for %i2 = 0 to %M {
|
||||
affine.for %i3 = 0 to %N {
|
||||
// CHECK: [[C3:%.*]] = constant dense<2.000000e+00> : vector<128xf32>
|
||||
// CHECK: vector.transfer_write [[C3]], {{.*}} {permutation_map = #[[map_proj_d0d1_d1]]} : vector<128xf32>, memref<?x?xf32>
|
||||
// CHECK: %[[C3:.*]] = constant dense<2.000000e+00> : vector<128xf32>
|
||||
// CHECK: vector.transfer_write %[[C3]], {{.*}} : vector<128xf32>, memref<?x?xf32>
|
||||
// non-scoped %f2
|
||||
affine.store %f2, %B[%i2, %i3] : memref<?x?xf32, 0>
|
||||
}
|
||||
}
|
||||
affine.for %i4 = 0 to %M {
|
||||
affine.for %i5 = 0 to %N {
|
||||
// CHECK: [[A5:%.*]] = vector.transfer_read %{{.*}}[{{.*}}], %{{.*}} {permutation_map = #[[map_proj_d0d1_d1]]} : memref<?x?xf32>, vector<128xf32>
|
||||
// CHECK: [[B5:%.*]] = vector.transfer_read %{{.*}}[{{.*}}], %{{.*}} {permutation_map = #[[map_proj_d0d1_d1]]} : memref<?x?xf32>, vector<128xf32>
|
||||
// CHECK: [[S5:%.*]] = addf [[A5]], [[B5]] : vector<128xf32>
|
||||
// CHECK: [[SPLAT1:%.*]] = constant dense<1.000000e+00> : vector<128xf32>
|
||||
// CHECK: [[S6:%.*]] = addf [[S5]], [[SPLAT1]] : vector<128xf32>
|
||||
// CHECK: [[SPLAT2:%.*]] = constant dense<2.000000e+00> : vector<128xf32>
|
||||
// CHECK: [[S7:%.*]] = addf [[S5]], [[SPLAT2]] : vector<128xf32>
|
||||
// CHECK: [[S8:%.*]] = addf [[S7]], [[S6]] : vector<128xf32>
|
||||
// CHECK: vector.transfer_write [[S8]], {{.*}} {permutation_map = #[[map_proj_d0d1_d1]]} : vector<128xf32>, memref<?x?xf32>
|
||||
// CHECK: %[[A5:.*]] = vector.transfer_read %{{.*}}[{{.*}}], %{{[a-zA-Z0-9_]*}} : memref<?x?xf32>, vector<128xf32>
|
||||
// CHECK: %[[B5:.*]] = vector.transfer_read %{{.*}}[{{.*}}], %{{[a-zA-Z0-9_]*}} : memref<?x?xf32>, vector<128xf32>
|
||||
// CHECK: %[[S5:.*]] = addf %[[A5]], %[[B5]] : vector<128xf32>
|
||||
// CHECK: %[[SPLAT1:.*]] = constant dense<1.000000e+00> : vector<128xf32>
|
||||
// CHECK: %[[S6:.*]] = addf %[[S5]], %[[SPLAT1]] : vector<128xf32>
|
||||
// CHECK: %[[SPLAT2:.*]] = constant dense<2.000000e+00> : vector<128xf32>
|
||||
// CHECK: %[[S7:.*]] = addf %[[S5]], %[[SPLAT2]] : vector<128xf32>
|
||||
// CHECK: %[[S8:.*]] = addf %[[S7]], %[[S6]] : vector<128xf32>
|
||||
// CHECK: vector.transfer_write %[[S8]], {{.*}} : vector<128xf32>, memref<?x?xf32>
|
||||
%a5 = affine.load %A[%i4, %i5] : memref<?x?xf32, 0>
|
||||
%b5 = affine.load %B[%i4, %i5] : memref<?x?xf32, 0>
|
||||
%s5 = addf %a5, %b5 : f32
|
||||
@@ -168,7 +167,6 @@ func @vec_rejected_2(%A : memref<?x?xf32>, %B : memref<?x?x?xf32>) {
|
||||
|
||||
// CHECK-LABEL: func @vec_rejected_3
|
||||
func @vec_rejected_3(%A : memref<?x?xf32>, %B : memref<?x?x?xf32>) {
|
||||
// CHECK-DAG: %{{.*}} = constant 0.0{{.*}}: f32
|
||||
// CHECK-DAG: [[C0:%[a-z0-9_]+]] = constant 0 : index
|
||||
// CHECK-DAG: [[ARG_M:%[0-9]+]] = dim %{{.*}}, 0 : memref<?x?xf32>
|
||||
// CHECK-DAG: [[ARG_N:%[0-9]+]] = dim %{{.*}}, 1 : memref<?x?xf32>
|
||||
@@ -180,7 +178,8 @@ func @vec_rejected_3(%A : memref<?x?xf32>, %B : memref<?x?x?xf32>) {
|
||||
//
|
||||
// CHECK:for [[IV4:%[arg0-9]+]] = 0 to [[ARG_M]] step 128 {
|
||||
// CHECK-NEXT: for [[IV5:%[arg0-9]*]] = 0 to [[ARG_N]] {
|
||||
// CHECK-NEXT: {{.*}} = vector.transfer_read %{{.*}}[%{{.*}}, %{{.*}}], %{{.*}} {permutation_map = #[[map_proj_d0d1_d1]]} : memref<?x?xf32>, vector<128xf32>
|
||||
// CHECK-NEXT: %{{.*}} = constant 0.0{{.*}}: f32
|
||||
// CHECK-NEXT: {{.*}} = vector.transfer_read %{{.*}}[%{{.*}}, %{{.*}}], %{{[a-zA-Z0-9_]*}} : memref<?x?xf32>, vector<128xf32>
|
||||
affine.for %i4 = 0 to %M { // vectorized
|
||||
affine.for %i5 = 0 to %N { // not vectorized, would vectorize with --test-fastest-varying=1
|
||||
%a5 = affine.load %A[%i5, %i4] : memref<?x?xf32>
|
||||
@@ -277,7 +276,6 @@ func @vec_rejected_7(%A : memref<?x?xf32>, %B : memref<?x?x?xf32>) {
|
||||
|
||||
// CHECK-LABEL: func @vec_rejected_8
|
||||
func @vec_rejected_8(%A : memref<?x?xf32>, %B : memref<?x?x?xf32>) {
|
||||
// CHECK-DAG: %{{.*}} = constant 0.0{{.*}}: f32
|
||||
// CHECK-DAG: %[[C0:[a-z0-9_]+]] = constant 0 : index
|
||||
// CHECK-DAG: [[ARG_M:%[0-9]+]] = dim %{{.*}}, 0 : memref<?x?xf32>
|
||||
// CHECK-DAG: [[ARG_N:%[0-9]+]] = dim %{{.*}}, 1 : memref<?x?xf32>
|
||||
@@ -291,6 +289,7 @@ func @vec_rejected_8(%A : memref<?x?xf32>, %B : memref<?x?x?xf32>) {
|
||||
// CHECK: for [[IV18:%[a-zA-Z0-9]+]] = 0 to [[ARG_M]] step 128
|
||||
// CHECK: %{{.*}} = affine.apply #map0(%{{.*}})
|
||||
// CHECK: %{{.*}} = affine.apply #map0(%{{.*}})
|
||||
// CHECK: %{{.*}} = constant 0.0{{.*}}: f32
|
||||
// CHECK: {{.*}} = vector.transfer_read %{{.*}}[%{{.*}}, %{{.*}}], %{{.*}} {permutation_map = #[[map_proj_d0d1_0]]} : memref<?x?xf32>, vector<128xf32>
|
||||
affine.for %i17 = 0 to %M { // not vectorized, the 1-D pattern that matched %{{.*}} in DFS post-order prevents vectorizing %{{.*}}
|
||||
affine.for %i18 = 0 to %M { // vectorized due to scalar -> vector
|
||||
@@ -302,7 +301,6 @@ func @vec_rejected_8(%A : memref<?x?xf32>, %B : memref<?x?x?xf32>) {
|
||||
|
||||
// CHECK-LABEL: func @vec_rejected_9
|
||||
func @vec_rejected_9(%A : memref<?x?xf32>, %B : memref<?x?x?xf32>) {
|
||||
// CHECK-DAG: %{{.*}} = constant 0.0{{.*}}: f32
|
||||
// CHECK-DAG: %[[C0:[a-z0-9_]+]] = constant 0 : index
|
||||
// CHECK-DAG: [[ARG_M:%[0-9]+]] = dim %{{.*}}, 0 : memref<?x?xf32>
|
||||
// CHECK-DAG: [[ARG_N:%[0-9]+]] = dim %{{.*}}, 1 : memref<?x?xf32>
|
||||
@@ -316,6 +314,7 @@ func @vec_rejected_9(%A : memref<?x?xf32>, %B : memref<?x?x?xf32>) {
|
||||
// CHECK: for [[IV18:%[a-zA-Z0-9]+]] = 0 to [[ARG_M]] step 128
|
||||
// CHECK: %{{.*}} = affine.apply #map0(%{{.*}})
|
||||
// CHECK-NEXT: %{{.*}} = affine.apply #map0(%{{.*}})
|
||||
// CHECK-NEXT: %{{.*}} = constant 0.0{{.*}}: f32
|
||||
// CHECK-NEXT: {{.*}} = vector.transfer_read %{{.*}}[%{{.*}}, %{{.*}}], %{{.*}} {permutation_map = #[[map_proj_d0d1_0]]} : memref<?x?xf32>, vector<128xf32>
|
||||
affine.for %i17 = 0 to %M { // not vectorized, the 1-D pattern that matched %i18 in DFS post-order prevents vectorizing %{{.*}}
|
||||
affine.for %i18 = 0 to %M { // vectorized due to scalar -> vector
|
||||
|
||||
@@ -54,7 +54,7 @@ func @vector_add_2d(%M : index, %N : index) -> f32 {
|
||||
affine.for %i0 = 0 to %M {
|
||||
affine.for %i1 = 0 to %N {
|
||||
// CHECK: [[C1:%.*]] = constant dense<1.000000e+00> : vector<32x256xf32>
|
||||
// CHECK: vector.transfer_write [[C1]], {{.*}} {permutation_map = #[[map_id2]]} : vector<32x256xf32>, memref<?x?xf32>
|
||||
// CHECK: vector.transfer_write [[C1]], {{.*}} : vector<32x256xf32>, memref<?x?xf32>
|
||||
// non-scoped %f1
|
||||
affine.store %f1, %A[%i0, %i1] : memref<?x?xf32, 0>
|
||||
}
|
||||
@@ -62,22 +62,22 @@ func @vector_add_2d(%M : index, %N : index) -> f32 {
|
||||
affine.for %i2 = 0 to %M {
|
||||
affine.for %i3 = 0 to %N {
|
||||
// CHECK: [[C3:%.*]] = constant dense<2.000000e+00> : vector<32x256xf32>
|
||||
// CHECK: vector.transfer_write [[C3]], {{.*}} {permutation_map = #[[map_id2]]} : vector<32x256xf32>, memref<?x?xf32>
|
||||
// CHECK: vector.transfer_write [[C3]], {{.*}} : vector<32x256xf32>, memref<?x?xf32>
|
||||
// non-scoped %f2
|
||||
affine.store %f2, %B[%i2, %i3] : memref<?x?xf32, 0>
|
||||
}
|
||||
}
|
||||
affine.for %i4 = 0 to %M {
|
||||
affine.for %i5 = 0 to %N {
|
||||
// CHECK: [[A5:%.*]] = vector.transfer_read %{{.*}}[{{.*}}], %{{.*}} {permutation_map = #[[map_id2]]} : memref<?x?xf32>, vector<32x256xf32>
|
||||
// CHECK: [[B5:%.*]] = vector.transfer_read %{{.*}}[{{.*}}], %{{.*}} {permutation_map = #[[map_id2]]} : memref<?x?xf32>, vector<32x256xf32>
|
||||
// CHECK: [[A5:%.*]] = vector.transfer_read %{{.*}}[{{.*}}], %{{.*}} : memref<?x?xf32>, vector<32x256xf32>
|
||||
// CHECK: [[B5:%.*]] = vector.transfer_read %{{.*}}[{{.*}}], %{{.*}} : memref<?x?xf32>, vector<32x256xf32>
|
||||
// CHECK: [[S5:%.*]] = addf [[A5]], [[B5]] : vector<32x256xf32>
|
||||
// CHECK: [[SPLAT1:%.*]] = constant dense<1.000000e+00> : vector<32x256xf32>
|
||||
// CHECK: [[S6:%.*]] = addf [[S5]], [[SPLAT1]] : vector<32x256xf32>
|
||||
// CHECK: [[SPLAT2:%.*]] = constant dense<2.000000e+00> : vector<32x256xf32>
|
||||
// CHECK: [[S7:%.*]] = addf [[S5]], [[SPLAT2]] : vector<32x256xf32>
|
||||
// CHECK: [[S8:%.*]] = addf [[S7]], [[S6]] : vector<32x256xf32>
|
||||
// CHECK: vector.transfer_write [[S8]], {{.*}} {permutation_map = #[[map_id2]]} : vector<32x256xf32>, memref<?x?xf32>
|
||||
// CHECK: vector.transfer_write [[S8]], {{.*}} : vector<32x256xf32>, memref<?x?xf32>
|
||||
//
|
||||
%a5 = affine.load %A[%i4, %i5] : memref<?x?xf32, 0>
|
||||
%b5 = affine.load %B[%i4, %i5] : memref<?x?xf32, 0>
|
||||
@@ -110,7 +110,7 @@ func @vectorize_matmul(%arg0: memref<?x?xf32>, %arg1: memref<?x?xf32>, %arg2: me
|
||||
// VECT: {{.*}} #[[map_id1]](%[[M]]) step 4 {
|
||||
// VECT-NEXT: {{.*}} #[[map_id1]](%[[N]]) step 8 {
|
||||
// VECT: %[[VC0:.*]] = constant dense<0.000000e+00> : vector<4x8xf32>
|
||||
// VECT-NEXT: vector.transfer_write %[[VC0]], %{{.*}}[%{{.*}}, %{{.*}}] {permutation_map = #[[map_id2]]} : vector<4x8xf32>, memref<?x?xf32>
|
||||
// VECT-NEXT: vector.transfer_write %[[VC0]], %{{.*}}[%{{.*}}, %{{.*}}] : vector<4x8xf32>, memref<?x?xf32>
|
||||
affine.for %i0 = affine_map<(d0) -> (d0)>(%c0) to affine_map<(d0) -> (d0)>(%M) {
|
||||
affine.for %i1 = affine_map<(d0) -> (d0)>(%c0) to affine_map<(d0) -> (d0)>(%N) {
|
||||
%cst = constant 0.000000e+00 : f32
|
||||
@@ -120,12 +120,12 @@ func @vectorize_matmul(%arg0: memref<?x?xf32>, %arg1: memref<?x?xf32>, %arg2: me
|
||||
// VECT: affine.for %[[I2:.*]] = #[[map_id1]](%[[C0]]) to #[[map_id1]](%[[M]]) step 4 {
|
||||
// VECT-NEXT: affine.for %[[I3:.*]] = #[[map_id1]](%[[C0]]) to #[[map_id1]](%[[N]]) step 8 {
|
||||
// VECT-NEXT: affine.for %[[I4:.*]] = #map5(%[[C0]]) to #[[map_id1]](%[[K]]) {
|
||||
// VECT-NEXT: %[[A:.*]] = vector.transfer_read %{{.*}}[%[[I4]], %[[I3]]], %{{.*}} {permutation_map = #[[map_proj_d0d1_zerod1]]} : memref<?x?xf32>, vector<4x8xf32>
|
||||
// VECT-NEXT: %[[B:.*]] = vector.transfer_read %{{.*}}[%[[I2]], %[[I4]]], %{{.*}} {permutation_map = #[[map_proj_d0d1_d0zero]]} : memref<?x?xf32>, vector<4x8xf32>
|
||||
// VECT: %[[A:.*]] = vector.transfer_read %{{.*}}[%[[I4]], %[[I3]]], %{{.*}} {permutation_map = #[[map_proj_d0d1_zerod1]]} : memref<?x?xf32>, vector<4x8xf32>
|
||||
// VECT: %[[B:.*]] = vector.transfer_read %{{.*}}[%[[I2]], %[[I4]]], %{{.*}} {permutation_map = #[[map_proj_d0d1_d0zero]]} : memref<?x?xf32>, vector<4x8xf32>
|
||||
// VECT-NEXT: %[[C:.*]] = mulf %[[B]], %[[A]] : vector<4x8xf32>
|
||||
// VECT-NEXT: %[[D:.*]] = vector.transfer_read %{{.*}}[%[[I2]], %[[I3]]], %{{.*}} {permutation_map = #[[map_id2]]} : memref<?x?xf32>, vector<4x8xf32>
|
||||
// VECT: %[[D:.*]] = vector.transfer_read %{{.*}}[%[[I2]], %[[I3]]], %{{.*}} : memref<?x?xf32>, vector<4x8xf32>
|
||||
// VECT-NEXT: %[[E:.*]] = addf %[[D]], %[[C]] : vector<4x8xf32>
|
||||
// VECT-NEXT: vector.transfer_write %[[E]], %{{.*}}[%[[I2]], %[[I3]]] {permutation_map = #[[map_id2]]} : vector<4x8xf32>, memref<?x?xf32>
|
||||
// VECT: vector.transfer_write %[[E]], %{{.*}}[%[[I2]], %[[I3]]] : vector<4x8xf32>, memref<?x?xf32>
|
||||
affine.for %i2 = affine_map<(d0) -> (d0)>(%c0) to affine_map<(d0) -> (d0)>(%M) {
|
||||
affine.for %i3 = affine_map<(d0) -> (d0)>(%c0) to affine_map<(d0) -> (d0)>(%N) {
|
||||
affine.for %i4 = affine_map<(d0) -> (d0)>(%c0) to affine_map<(d0) -> (d0)>(%K) {
|
||||
|
||||
@@ -12,7 +12,7 @@ func @vec3d(%A : memref<?x?x?xf32>) {
|
||||
// CHECK: affine.for %{{.*}} = 0 to %{{.*}} step 32 {
|
||||
// CHECK: affine.for %{{.*}} = 0 to %{{.*}} step 64 {
|
||||
// CHECK: affine.for %{{.*}} = 0 to %{{.*}} step 256 {
|
||||
// CHECK: %{{.*}} = vector.transfer_read %{{.*}}[%{{.*}}, %{{.*}}, %{{.*}}], %{{.*}} {permutation_map = #[[map_proj_d0d1d2_d0d1d2]]} : memref<?x?x?xf32>, vector<32x64x256xf32>
|
||||
// CHECK: %{{.*}} = vector.transfer_read %{{.*}}[%{{.*}}, %{{.*}}, %{{.*}}], %{{.*}} : memref<?x?x?xf32>, vector<32x64x256xf32>
|
||||
affine.for %t0 = 0 to %0 {
|
||||
affine.for %t1 = 0 to %0 {
|
||||
affine.for %i0 = 0 to %0 {
|
||||
|
||||
@@ -238,12 +238,32 @@ func @outerproduct_operand_3_result_type_generic(%arg0: vector<4xf32>, %arg1: ve
|
||||
func @test_vector.transfer_read(%arg0: memref<?x?xf32>) {
|
||||
%c3 = constant 3 : index
|
||||
%cst = constant 3.0 : f32
|
||||
// expected-error@+1 {{two types required}}
|
||||
// expected-error@+1 {{requires two types}}
|
||||
%0 = vector.transfer_read %arg0[%c3, %c3], %cst { permutation_map = affine_map<()->(0)> } : memref<?x?xf32>
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
func @test_vector.transfer_read(%arg0: vector<4x3xf32>) {
|
||||
%c3 = constant 3 : index
|
||||
%f0 = constant 0.0 : f32
|
||||
%vf0 = splat %f0 : vector<4x3xf32>
|
||||
// expected-error@+1 {{ requires memref type}}
|
||||
%0 = vector.transfer_read %arg0[%c3, %c3], %vf0 : vector<4x3xf32>, vector<1x1x2x3xf32>
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
func @test_vector.transfer_read(%arg0: memref<4x3xf32>) {
|
||||
%c3 = constant 3 : index
|
||||
%f0 = constant 0.0 : f32
|
||||
%vf0 = splat %f0 : vector<4x3xf32>
|
||||
// expected-error@+1 {{ requires vector type}}
|
||||
%0 = vector.transfer_read %arg0[%c3, %c3], %vf0 : memref<4x3xf32>, f32
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
func @test_vector.transfer_read(%arg0: memref<?x?xf32>) {
|
||||
%c3 = constant 3 : index
|
||||
%cst = constant 3.0 : f32
|
||||
@@ -253,15 +273,6 @@ func @test_vector.transfer_read(%arg0: memref<?x?xf32>) {
|
||||
|
||||
// -----
|
||||
|
||||
func @test_vector.transfer_read(%arg0: memref<?x?xf32>) {
|
||||
%c3 = constant 3 : index
|
||||
%cst = constant 3.0 : f32
|
||||
// expected-error@+1 {{requires attribute 'permutation_map'}}
|
||||
%0 = vector.transfer_read %arg0[%c3, %c3], %cst {perm = affine_map<(d0)->(d0)>} : memref<?x?xf32>, vector<128xf32>
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
func @test_vector.transfer_read(%arg0: memref<?x?xf32>) {
|
||||
%c3 = constant 3 : index
|
||||
%cst = constant 3.0 : f32
|
||||
@@ -337,6 +348,35 @@ func @test_vector.transfer_read(%arg0: memref<?x?xvector<4x3xf32>>) {
|
||||
|
||||
// -----
|
||||
|
||||
func @test_vector.transfer_write(%arg0: memref<?x?xf32>) {
|
||||
%c3 = constant 3 : index
|
||||
%cst = constant 3.0 : f32
|
||||
// expected-error@+1 {{requires two types}}
|
||||
vector.transfer_write %arg0, %arg0[%c3, %c3] : memref<?x?xf32>
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
func @test_vector.transfer_write(%arg0: memref<vector<4x3xf32>>) {
|
||||
%c3 = constant 3 : index
|
||||
%f0 = constant 0.0 : f32
|
||||
%vf0 = splat %f0 : vector<4x3xf32>
|
||||
// expected-error@+1 {{ requires vector type}}
|
||||
vector.transfer_write %arg0, %arg0[%c3, %c3] : memref<vector<4x3xf32>>, vector<4x3xf32>
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
func @test_vector.transfer_write(%arg0: vector<4x3xf32>) {
|
||||
%c3 = constant 3 : index
|
||||
%f0 = constant 0.0 : f32
|
||||
%vf0 = splat %f0 : vector<4x3xf32>
|
||||
// expected-error@+1 {{ requires memref type}}
|
||||
vector.transfer_write %arg0, %arg0[%c3, %c3] : vector<4x3xf32>, f32
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
func @test_vector.transfer_write(%arg0: memref<?x?xf32>) {
|
||||
%c3 = constant 3 : index
|
||||
%cst = constant dense<3.0> : vector<128 x f32>
|
||||
@@ -355,15 +395,6 @@ func @test_vector.transfer_write(%arg0: memref<?x?xf32>) {
|
||||
|
||||
// -----
|
||||
|
||||
func @test_vector.transfer_write(%arg0: memref<?x?xf32>) {
|
||||
%c3 = constant 3 : index
|
||||
%cst = constant dense<3.0> : vector<128 x f32>
|
||||
// expected-error@+1 {{requires attribute 'permutation_map'}}
|
||||
vector.transfer_write %cst, %arg0[%c3, %c3] {perm = affine_map<(d0)->(d0)>} : vector<128xf32>, memref<?x?xf32>
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
func @test_vector.transfer_write(%arg0: memref<?x?xf32>) {
|
||||
%c3 = constant 3 : index
|
||||
%cst = constant dense<3.0> : vector<128 x f32>
|
||||
|
||||
@@ -20,14 +20,14 @@ func @vector_transfer_ops(%arg0: memref<?x?xf32>,
|
||||
%2 = vector.transfer_read %arg0[%c3, %c3], %cst {permutation_map = affine_map<(d0, d1)->(d0)>} : memref<?x?xf32>, vector<128xf32>
|
||||
// CHECK: vector.transfer_read
|
||||
%3 = vector.transfer_read %arg0[%c3, %c3], %cst {permutation_map = affine_map<(d0, d1)->(d1)>} : memref<?x?xf32>, vector<128xf32>
|
||||
// CHECK: vector.transfer_read %{{.*}}[%[[C3]], %[[C3]]], %{{.*}} {permutation_map = #[[MAP0]]} : memref<?x?xvector<4x3xf32>>, vector<1x1x4x3xf32>
|
||||
// CHECK: vector.transfer_read %{{.*}}[%[[C3]], %[[C3]]], %{{.*}} : memref<?x?xvector<4x3xf32>>, vector<1x1x4x3xf32>
|
||||
%4 = vector.transfer_read %arg1[%c3, %c3], %vf0 {permutation_map = affine_map<(d0, d1)->(d0, d1)>} : memref<?x?xvector<4x3xf32>>, vector<1x1x4x3xf32>
|
||||
|
||||
// CHECK: vector.transfer_write
|
||||
vector.transfer_write %0, %arg0[%c3, %c3] {permutation_map = affine_map<(d0, d1)->(d0)>} : vector<128xf32>, memref<?x?xf32>
|
||||
// CHECK: vector.transfer_write
|
||||
vector.transfer_write %1, %arg0[%c3, %c3] {permutation_map = affine_map<(d0, d1)->(d1, d0)>} : vector<3x7xf32>, memref<?x?xf32>
|
||||
// CHECK: vector.transfer_write %{{.*}}, %{{.*}}[%[[C3]], %[[C3]]] {permutation_map = #[[MAP0]]} : vector<1x1x4x3xf32>, memref<?x?xvector<4x3xf32>>
|
||||
// CHECK: vector.transfer_write %{{.*}}, %{{.*}}[%[[C3]], %[[C3]]] : vector<1x1x4x3xf32>, memref<?x?xvector<4x3xf32>>
|
||||
vector.transfer_write %4, %arg1[%c3, %c3] {permutation_map = affine_map<(d0, d1)->(d0, d1)>} : vector<1x1x4x3xf32>, memref<?x?xvector<4x3xf32>>
|
||||
|
||||
return
|
||||
|
||||
@@ -231,26 +231,26 @@ func @contraction4x4_ikj(%arg0 : vector<4x2xf32>, %arg1 : vector<2x4xf32>,
|
||||
|
||||
// Check LHS vector.transfer read is split for each user.
|
||||
|
||||
// CHECK: %[[VTR0:.*]] = vector.transfer_read %{{.*}}[%[[C0]], %[[C0]]], %{{.*}} {permutation_map = #[[MAP0]]} : memref<4x2xf32>, vector<2x2xf32>
|
||||
// CHECK-NEXT: %[[VTR1:.*]] = vector.transfer_read %{{.*}}[%[[C2]], %[[C0]]], %{{.*}} {permutation_map = #[[MAP0]]} : memref<4x2xf32>, vector<2x2xf32>
|
||||
// CHECK: %[[VTR0:.*]] = vector.transfer_read %{{.*}}[%[[C0]], %[[C0]]], %{{.*}} : memref<4x2xf32>, vector<2x2xf32>
|
||||
// CHECK-NEXT: %[[VTR1:.*]] = vector.transfer_read %{{.*}}[%[[C2]], %[[C0]]], %{{.*}} : memref<4x2xf32>, vector<2x2xf32>
|
||||
|
||||
// CHECK-NEXT: %[[VTR2:.*]] = vector.transfer_read %{{.*}}[%[[C0]], %[[C0]]], %{{.*}} {permutation_map = #[[MAP0]]} : memref<2x4xf32>, vector<2x2xf32>
|
||||
// CHECK-NEXT: %[[VTR3:.*]] = vector.transfer_read %{{.*}}[%[[C0]], %[[C2]]], %{{.*}} {permutation_map = #[[MAP0]]} : memref<2x4xf32>, vector<2x2xf32>
|
||||
// CHECK-NEXT: %[[VTR2:.*]] = vector.transfer_read %{{.*}}[%[[C0]], %[[C0]]], %{{.*}} : memref<2x4xf32>, vector<2x2xf32>
|
||||
// CHECK-NEXT: %[[VTR3:.*]] = vector.transfer_read %{{.*}}[%[[C0]], %[[C2]]], %{{.*}} : memref<2x4xf32>, vector<2x2xf32>
|
||||
|
||||
// CHECK-NEXT: %[[VTR4:.*]] = vector.transfer_read %{{.*}}[%[[C0]], %[[C0]]], %{{.*}} {permutation_map = #[[MAP0]]} : memref<4x4xf32>, vector<2x2xf32>
|
||||
// CHECK-NEXT: %[[VTR5:.*]] = vector.transfer_read %{{.*}}[%[[C0]], %[[C2]]], %{{.*}} {permutation_map = #[[MAP0]]} : memref<4x4xf32>, vector<2x2xf32>
|
||||
// CHECK-NEXT: %[[VTR6:.*]] = vector.transfer_read %{{.*}}[%[[C2]], %[[C0]]], %{{.*}} {permutation_map = #[[MAP0]]} : memref<4x4xf32>, vector<2x2xf32>
|
||||
// CHECK-NEXT: %[[VTR7:.*]] = vector.transfer_read %{{.*}}[%[[C2]], %[[C2]]], %{{.*}} {permutation_map = #[[MAP0]]} : memref<4x4xf32>, vector<2x2xf32>
|
||||
// CHECK-NEXT: %[[VTR4:.*]] = vector.transfer_read %{{.*}}[%[[C0]], %[[C0]]], %{{.*}} : memref<4x4xf32>, vector<2x2xf32>
|
||||
// CHECK-NEXT: %[[VTR5:.*]] = vector.transfer_read %{{.*}}[%[[C0]], %[[C2]]], %{{.*}} : memref<4x4xf32>, vector<2x2xf32>
|
||||
// CHECK-NEXT: %[[VTR6:.*]] = vector.transfer_read %{{.*}}[%[[C2]], %[[C0]]], %{{.*}} : memref<4x4xf32>, vector<2x2xf32>
|
||||
// CHECK-NEXT: %[[VTR7:.*]] = vector.transfer_read %{{.*}}[%[[C2]], %[[C2]]], %{{.*}} : memref<4x4xf32>, vector<2x2xf32>
|
||||
|
||||
// CHECK-NEXT: %[[R0:.*]] = vector.contract {indexing_maps = [#map2, #map3, #map0], iterator_types = ["parallel", "reduction", "parallel"]} %[[VTR0]], %[[VTR2]], %[[VTR4]] : vector<2x2xf32>, vector<2x2xf32> into vector<2x2xf32>
|
||||
// CHECK-NEXT: %[[R1:.*]] = vector.contract {indexing_maps = [#map2, #map3, #map0], iterator_types = ["parallel", "reduction", "parallel"]} %[[VTR0]], %[[VTR3]], %[[VTR5]] : vector<2x2xf32>, vector<2x2xf32> into vector<2x2xf32>
|
||||
// CHECK-NEXT: %[[R2:.*]] = vector.contract {indexing_maps = [#map2, #map3, #map0], iterator_types = ["parallel", "reduction", "parallel"]} %[[VTR1]], %[[VTR2]], %[[VTR6]] : vector<2x2xf32>, vector<2x2xf32> into vector<2x2xf32>
|
||||
// CHECK-NEXT: %[[R3:.*]] = vector.contract {indexing_maps = [#map2, #map3, #map0], iterator_types = ["parallel", "reduction", "parallel"]} %[[VTR1]], %[[VTR3]], %[[VTR7]] : vector<2x2xf32>, vector<2x2xf32> into vector<2x2xf32>
|
||||
|
||||
// CHECK-NEXT: vector.transfer_write %[[R0]], %{{.*}}[%[[C0]], %[[C0]]] {permutation_map = #[[MAP0]]} : vector<2x2xf32>, memref<4x4xf32>
|
||||
// CHECK-NEXT: vector.transfer_write %[[R1]], %{{.*}}[%[[C0]], %[[C2]]] {permutation_map = #[[MAP0]]} : vector<2x2xf32>, memref<4x4xf32>
|
||||
// CHECK-NEXT: vector.transfer_write %[[R2]], %{{.*}}[%[[C2]], %[[C0]]] {permutation_map = #[[MAP0]]} : vector<2x2xf32>, memref<4x4xf32>
|
||||
// CHECK-NEXT: vector.transfer_write %[[R3]], %{{.*}}[%[[C2]], %[[C2]]] {permutation_map = #[[MAP0]]} : vector<2x2xf32>, memref<4x4xf32>
|
||||
// CHECK-NEXT: vector.transfer_write %[[R0]], %{{.*}}[%[[C0]], %[[C0]]] : vector<2x2xf32>, memref<4x4xf32>
|
||||
// CHECK-NEXT: vector.transfer_write %[[R1]], %{{.*}}[%[[C0]], %[[C2]]] : vector<2x2xf32>, memref<4x4xf32>
|
||||
// CHECK-NEXT: vector.transfer_write %[[R2]], %{{.*}}[%[[C2]], %[[C0]]] : vector<2x2xf32>, memref<4x4xf32>
|
||||
// CHECK-NEXT: vector.transfer_write %[[R3]], %{{.*}}[%[[C2]], %[[C2]]] : vector<2x2xf32>, memref<4x4xf32>
|
||||
// CHECK-NEXT: return
|
||||
|
||||
func @contraction4x4_ikj_xfer_read(%arg0 : memref<4x2xf32>,
|
||||
@@ -425,10 +425,10 @@ func @cancelling_shape_cast_ops(%arg0 : vector<2x4xf32>) -> vector<2x4xf32> {
|
||||
// CHECK-LABEL: func @vector_transfers_vector_element_type
|
||||
// CHECK: %[[C0:.*]] = constant 0 : index
|
||||
// CHECK: %[[C1:.*]] = constant 1 : index
|
||||
// CHECK: %[[VTR0:.*]] = vector.transfer_read %{{.*}}[%[[C0]], %[[C0]], %[[C0]]], %{{.*}} {permutation_map = #[[MAP1]]} : memref<6x2x1xvector<2x4xf32>>, vector<1x1x2x4xf32>
|
||||
// CHECK-NEXT: %[[VTR1:.*]] = vector.transfer_read %{{.*}}[%[[C0]], %[[C1]], %[[C0]]], %{{.*}} {permutation_map = #[[MAP1]]} : memref<6x2x1xvector<2x4xf32>>, vector<1x1x2x4xf32>
|
||||
// CHECK-NEXT: vector.transfer_write %[[VTR0]], %{{.*}}[%[[C0]], %[[C0]], %[[C0]]] {permutation_map = #[[MAP1]]} : vector<1x1x2x4xf32>, memref<6x2x1xvector<2x4xf32>>
|
||||
// CHECK-NEXT: vector.transfer_write %[[VTR1]], %{{.*}}[%[[C0]], %[[C1]], %[[C0]]] {permutation_map = #[[MAP1]]} : vector<1x1x2x4xf32>, memref<6x2x1xvector<2x4xf32>>
|
||||
// CHECK: %[[VTR0:.*]] = vector.transfer_read %{{.*}}[%[[C0]], %[[C0]], %[[C0]]], %{{.*}} : memref<6x2x1xvector<2x4xf32>>, vector<1x1x2x4xf32>
|
||||
// CHECK-NEXT: %[[VTR1:.*]] = vector.transfer_read %{{.*}}[%[[C0]], %[[C1]], %[[C0]]], %{{.*}} : memref<6x2x1xvector<2x4xf32>>, vector<1x1x2x4xf32>
|
||||
// CHECK-NEXT: vector.transfer_write %[[VTR0]], %{{.*}}[%[[C0]], %[[C0]], %[[C0]]] : vector<1x1x2x4xf32>, memref<6x2x1xvector<2x4xf32>>
|
||||
// CHECK-NEXT: vector.transfer_write %[[VTR1]], %{{.*}}[%[[C0]], %[[C1]], %[[C0]]] : vector<1x1x2x4xf32>, memref<6x2x1xvector<2x4xf32>>
|
||||
|
||||
func @vector_transfers_vector_element_type() {
|
||||
%c0 = constant 0 : index
|
||||
|
||||
Reference in New Issue
Block a user