[Mlir-commits] [mlir] 6825bfe - [mlir][Vector] NFC - Drop vector EDSC usage
Nicolas Vasilache
llvmlistbot at llvm.org
Wed May 19 05:49:36 PDT 2021
Author: Nicolas Vasilache
Date: 2021-05-19T12:44:38Z
New Revision: 6825bfe23e3829c81574e7d5d41887ca2dae4bef
URL: https://github.com/llvm/llvm-project/commit/6825bfe23e3829c81574e7d5d41887ca2dae4bef
DIFF: https://github.com/llvm/llvm-project/commit/6825bfe23e3829c81574e7d5d41887ca2dae4bef.diff
LOG: [mlir][Vector] NFC - Drop vector EDSC usage
Drop the vector dialect EDSC subdirectory and update all uses.
Added:
Modified:
mlir/include/mlir/Dialect/Affine/IR/AffineOps.h
mlir/lib/Conversion/VectorToSCF/VectorToSCF.cpp
mlir/lib/Dialect/Affine/IR/AffineOps.cpp
mlir/lib/Dialect/Linalg/Transforms/Interchange.cpp
mlir/lib/Dialect/Linalg/Transforms/Transforms.cpp
mlir/lib/Dialect/Linalg/Transforms/Vectorization.cpp
mlir/lib/Dialect/Vector/CMakeLists.txt
mlir/lib/Dialect/Vector/VectorTransforms.cpp
mlir/test/CMakeLists.txt
Removed:
mlir/include/mlir/Dialect/Vector/EDSC/Builders.h
mlir/include/mlir/Dialect/Vector/EDSC/Intrinsics.h
mlir/lib/Dialect/Vector/EDSC/Builders.cpp
mlir/test/EDSC/CMakeLists.txt
mlir/test/EDSC/builder-api-test.cpp
mlir/test/EDSC/lit.local.cfg
################################################################################
diff --git a/mlir/include/mlir/Dialect/Affine/IR/AffineOps.h b/mlir/include/mlir/Dialect/Affine/IR/AffineOps.h
index a614ec61c0b3..164e8b3b83ee 100644
--- a/mlir/include/mlir/Dialect/Affine/IR/AffineOps.h
+++ b/mlir/include/mlir/Dialect/Affine/IR/AffineOps.h
@@ -356,7 +356,10 @@ void canonicalizeSetAndOperands(IntegerSet *set,
/// other AffineApplyOps supplying those operands. The operands of the resulting
/// AffineApplyOp do not change the length of AffineApplyOp chains.
AffineApplyOp makeComposedAffineApply(OpBuilder &b, Location loc, AffineMap map,
- ArrayRef<Value> operands);
+ ValueRange operands);
+/// Variant of `makeComposedAffineApply` which infers the AffineMap from `e`.
+AffineApplyOp makeComposedAffineApply(OpBuilder &b, Location loc, AffineExpr e,
+ ValueRange values);
/// Given an affine map `map` and its input `operands`, this method composes
/// into `map`, maps of AffineApplyOps whose results are the values in
diff --git a/mlir/include/mlir/Dialect/Vector/EDSC/Builders.h b/mlir/include/mlir/Dialect/Vector/EDSC/Builders.h
deleted file mode 100644
index 65767af61b2d..000000000000
--- a/mlir/include/mlir/Dialect/Vector/EDSC/Builders.h
+++ /dev/null
@@ -1,52 +0,0 @@
-//===- Builders.h - MLIR Declarative Vector Builders ------------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// Provides intuitive composable interfaces for building structured MLIR
-// snippets in a declarative fashion.
-//
-//===----------------------------------------------------------------------===//
-#ifndef MLIR_DIALECT_VECTOR_EDSC_BUILDERS_H_
-#define MLIR_DIALECT_VECTOR_EDSC_BUILDERS_H_
-
-#include "mlir/Dialect/Utils/StructuredOpsUtils.h"
-#include "mlir/Dialect/Vector/VectorOps.h"
-#include "mlir/EDSC/Builders.h"
-#include "mlir/IR/AffineExpr.h"
-#include "mlir/IR/Builders.h"
-
-namespace mlir {
-namespace edsc {
-namespace ops {
-
-/// Build a generic vector contraction, that is a `vector.contract` op with
-/// specified `iteratorTypes`. The client is responsible for specifying proper
-/// indexings when creating the StructuredIndexed.
-/// The computation represents a notional (A * B + C) where indexings specify
-/// which dimensions are reduced and reordered.
-/// Return the result of the `vector.contract` op
-///
-/// Prerequisites:
-/// A, B and C capture values of proper vector types, and indexing expressions
-/// that match semantics of the `vector.contract` op.
-Value vector_contraction(StructuredIndexed A, StructuredIndexed B,
- StructuredIndexed C,
- ArrayRef<IteratorType> iteratorTypes);
-
-/// Build a generic vector contraction that computes a matmul on vectors.
-/// Return the result of C(i, j) + sum_k {A(i, k) * B(k, j)} on vectors.
-///
-/// Prerequisites:
-/// A, B and C capture values of proper vector types. For instance
-/// `A: vector<4x8xf32>`, `B: vector<8x16f32>` and `C: vector<4x16xf32>`.
-Value vector_contraction_matmul(Value A, Value B, Value C);
-
-} // namespace ops
-} // namespace edsc
-} // namespace mlir
-
-#endif // MLIR_DIALECT_VECTOR_EDSC_BUILDERS_H_
diff --git a/mlir/include/mlir/Dialect/Vector/EDSC/Intrinsics.h b/mlir/include/mlir/Dialect/Vector/EDSC/Intrinsics.h
deleted file mode 100644
index 269d9c1b27af..000000000000
--- a/mlir/include/mlir/Dialect/Vector/EDSC/Intrinsics.h
+++ /dev/null
@@ -1,41 +0,0 @@
-//===- Intrinsics.h - MLIR EDSC Intrinsics for Vector -----------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-#ifndef MLIR_DIALECT_VECTOR_EDSC_INTRINSICS_H_
-#define MLIR_DIALECT_VECTOR_EDSC_INTRINSICS_H_
-
-#include "mlir/Dialect/Vector/EDSC/Builders.h"
-
-namespace mlir {
-namespace edsc {
-namespace intrinsics {
-
-using vector_broadcast = ValueBuilder<vector::BroadcastOp>;
-using vector_contract = ValueBuilder<vector::ContractionOp>;
-using vector_extract = ValueBuilder<vector::ExtractOp>;
-using vector_extract_element = ValueBuilder<vector::ExtractElementOp>;
-using vector_extract_slices = ValueBuilder<vector::ExtractSlicesOp>;
-using vector_extract_strided_slice =
- ValueBuilder<vector::ExtractStridedSliceOp>;
-using vector_fma = ValueBuilder<vector::FMAOp>;
-using vector_insert = ValueBuilder<vector::InsertOp>;
-using vector_insert_element = ValueBuilder<vector::InsertElementOp>;
-using vector_insert_slices = ValueBuilder<vector::InsertSlicesOp>;
-using vector_insert_strided_slice = ValueBuilder<vector::InsertStridedSliceOp>;
-using vector_matmul = ValueBuilder<vector::MatmulOp>;
-using vector_outerproduct = ValueBuilder<vector::OuterProductOp>;
-using vector_print = OperationBuilder<vector::PrintOp>;
-using vector_transfer_read = ValueBuilder<vector::TransferReadOp>;
-using vector_transfer_write = OperationBuilder<vector::TransferWriteOp>;
-using vector_transpose = ValueBuilder<vector::TransposeOp>;
-using vector_type_cast = ValueBuilder<vector::TypeCastOp>;
-
-} // namespace intrinsics
-} // namespace edsc
-} // namespace mlir
-
-#endif // MLIR_DIALECT_VECTOR_EDSC_INTRINSICS_H_
diff --git a/mlir/lib/Conversion/VectorToSCF/VectorToSCF.cpp b/mlir/lib/Conversion/VectorToSCF/VectorToSCF.cpp
index 54783a7a3992..bef847c1ffac 100644
--- a/mlir/lib/Conversion/VectorToSCF/VectorToSCF.cpp
+++ b/mlir/lib/Conversion/VectorToSCF/VectorToSCF.cpp
@@ -15,21 +15,18 @@
#include "mlir/Conversion/VectorToSCF/VectorToSCF.h"
#include "../PassDetail.h"
-#include "mlir/Dialect/Affine/EDSC/Intrinsics.h"
-#include "mlir/Dialect/MemRef/EDSC/Intrinsics.h"
-#include "mlir/Dialect/SCF/EDSC/Intrinsics.h"
-#include "mlir/Dialect/StandardOps/EDSC/Intrinsics.h"
-#include "mlir/Dialect/Vector/EDSC/Intrinsics.h"
+#include "mlir/Dialect/Affine/IR/AffineOps.h"
+#include "mlir/Dialect/Affine/Utils.h"
+#include "mlir/Dialect/SCF/SCF.h"
#include "mlir/Dialect/Vector/VectorOps.h"
#include "mlir/Dialect/Vector/VectorUtils.h"
#include "mlir/IR/Builders.h"
+#include "mlir/IR/ImplicitLocOpBuilder.h"
#include "mlir/Pass/Pass.h"
#include "mlir/Transforms/GreedyPatternRewriteDriver.h"
#include "mlir/Transforms/Passes.h"
using namespace mlir;
-using namespace mlir::edsc;
-using namespace mlir::edsc::intrinsics;
using vector::TransferReadOp;
using vector::TransferWriteOp;
@@ -67,10 +64,10 @@ static Optional<int64_t> unpackedDim(OpTy xferOp) {
/// map is identical to the current permutation map, but the first result is
/// omitted.
template <typename OpTy>
-static AffineMap unpackedPermutationMap(OpTy xferOp, OpBuilder &builder) {
+static AffineMap unpackedPermutationMap(OpBuilder &b, OpTy xferOp) {
auto map = xferOp.permutation_map();
return AffineMap::get(map.getNumDims(), 0, map.getResults().drop_front(),
- builder.getContext());
+ b.getContext());
}
/// Calculate the indices for the new vector transfer op.
@@ -80,7 +77,7 @@ static AffineMap unpackedPermutationMap(OpTy xferOp, OpBuilder &builder) {
/// ^^^^^^
/// `iv` is the iteration variable of the (new) surrounding loop.
template <typename OpTy>
-static void getXferIndices(OpTy xferOp, Value iv,
+static void getXferIndices(OpBuilder &b, OpTy xferOp, Value iv,
SmallVector<Value, 8> &indices) {
typename OpTy::Adaptor adaptor(xferOp);
// Corresponding memref dim of the vector dim that is unpacked.
@@ -88,19 +85,23 @@ static void getXferIndices(OpTy xferOp, Value iv,
auto prevIndices = adaptor.indices();
indices.append(prevIndices.begin(), prevIndices.end());
+ Location loc = xferOp.getLoc();
bool isBroadcast = !dim.hasValue();
if (!isBroadcast) {
- using edsc::op::operator+;
- indices[dim.getValue()] = adaptor.indices()[dim.getValue()] + iv;
+ AffineExpr d0, d1;
+ bindDims(xferOp.getContext(), d0, d1);
+ Value offset = adaptor.indices()[dim.getValue()];
+ indices[dim.getValue()] =
+ makeComposedAffineApply(b, loc, d0 + d1, {offset, iv});
}
}
-static void maybeYieldValue(bool hasRetVal, OpBuilder builder, Location loc,
+static void maybeYieldValue(OpBuilder &b, Location loc, bool hasRetVal,
Value value) {
if (hasRetVal) {
- builder.create<scf::YieldOp>(loc, value);
+ b.create<scf::YieldOp>(loc, value);
} else {
- builder.create<scf::YieldOp>(loc);
+ b.create<scf::YieldOp>(loc);
}
}
@@ -111,7 +112,7 @@ static void maybeYieldValue(bool hasRetVal, OpBuilder builder, Location loc,
/// computed and attached to the new transfer op in the pattern.)
/// * The to-be-unpacked dim of xferOp is a broadcast.
template <typename OpTy>
-static Value generateMaskCheck(OpBuilder &builder, OpTy xferOp, Value iv) {
+static Value generateMaskCheck(OpBuilder &b, OpTy xferOp, Value iv) {
if (!xferOp.mask())
return Value();
if (xferOp.getMaskType().getRank() != 1)
@@ -119,8 +120,10 @@ static Value generateMaskCheck(OpBuilder &builder, OpTy xferOp, Value iv) {
if (xferOp.isBroadcastDim(0))
return Value();
- auto ivI32 = std_index_cast(IntegerType::get(builder.getContext(), 32), iv);
- return vector_extract_element(xferOp.mask(), ivI32).value;
+ Location loc = xferOp.getLoc();
+ Value ivI32 =
+ b.create<IndexCastOp>(loc, IntegerType::get(b.getContext(), 32), iv);
+ return b.create<vector::ExtractElementOp>(loc, xferOp.mask(), ivI32);
}
/// Helper function TransferOpConversion and TransferOp1dConversion.
@@ -149,7 +152,7 @@ static Value generateMaskCheck(OpBuilder &builder, OpTy xferOp, Value iv) {
/// `resultTypes`.
template <typename OpTy>
static Value generateInBoundsCheck(
- OpTy xferOp, Value iv, OpBuilder &builder, Optional<int64_t> dim,
+ OpBuilder &b, OpTy xferOp, Value iv, Optional<int64_t> dim,
TypeRange resultTypes,
function_ref<Value(OpBuilder &, Location)> inBoundsCase,
function_ref<Value(OpBuilder &, Location)> outOfBoundsCase = nullptr) {
@@ -158,38 +161,39 @@ static Value generateInBoundsCheck(
// Condition check 1: Access in-bounds?
bool isBroadcast = !dim.hasValue(); // No in-bounds check for broadcasts.
+ Location loc = xferOp.getLoc();
+ ImplicitLocOpBuilder lb(xferOp.getLoc(), b);
if (!xferOp.isDimInBounds(0) && !isBroadcast) {
- auto memrefDim =
- memref_dim(xferOp.source(), std_constant_index(dim.getValue()));
- using edsc::op::operator+;
- auto memrefIdx = xferOp.indices()[dim.getValue()] + iv;
- cond = std_cmpi_sgt(memrefDim.value, memrefIdx);
+ Value memrefDim = lb.create<memref::DimOp>(xferOp.source(), *dim);
+ AffineExpr d0, d1;
+ bindDims(xferOp.getContext(), d0, d1);
+ Value base = xferOp.indices()[dim.getValue()];
+ Value memrefIdx = makeComposedAffineApply(b, loc, d0 + d1, {base, iv});
+ cond = lb.create<CmpIOp>(CmpIPredicate::sgt, memrefDim, memrefIdx);
}
// Condition check 2: Masked in?
- if (auto maskCond = generateMaskCheck(builder, xferOp, iv)) {
- if (cond) {
- cond = builder.create<AndOp>(xferOp.getLoc(), cond, maskCond);
- } else {
+ if (auto maskCond = generateMaskCheck(b, xferOp, iv)) {
+ if (cond)
+ cond = lb.create<AndOp>(cond, maskCond);
+ else
cond = maskCond;
- }
}
// If the condition is non-empty, generate an SCF::IfOp.
if (cond) {
- auto check = builder.create<scf::IfOp>(
- xferOp.getLoc(), resultTypes, cond,
+ auto check = lb.create<scf::IfOp>(
+ resultTypes, cond,
/*thenBuilder=*/
- [&](OpBuilder &builder, Location loc) {
- maybeYieldValue(hasRetVal, builder, loc, inBoundsCase(builder, loc));
+ [&](OpBuilder &b, Location loc) {
+ maybeYieldValue(b, loc, hasRetVal, inBoundsCase(b, loc));
},
/*elseBuilder=*/
- [&](OpBuilder &builder, Location loc) {
+ [&](OpBuilder &b, Location loc) {
if (outOfBoundsCase) {
- maybeYieldValue(hasRetVal, builder, loc,
- outOfBoundsCase(builder, loc));
+ maybeYieldValue(b, loc, hasRetVal, outOfBoundsCase(b, loc));
} else {
- builder.create<scf::YieldOp>(loc);
+ b.create<scf::YieldOp>(loc);
}
});
@@ -197,45 +201,45 @@ static Value generateInBoundsCheck(
}
// Condition is empty, no need for an SCF::IfOp.
- return inBoundsCase(builder, xferOp.getLoc());
+ return inBoundsCase(b, loc);
}
/// In this function variant, `inBoundsCase` and `outOfBoundsCase` do not have
/// a return value. Consequently, this function does not have a return value.
template <typename OpTy>
static void generateInBoundsCheck(
- OpTy xferOp, Value iv, OpBuilder &builder, Optional<int64_t> dim,
+ OpBuilder &b, OpTy xferOp, Value iv, Optional<int64_t> dim,
function_ref<void(OpBuilder &, Location)> inBoundsCase,
function_ref<void(OpBuilder &, Location)> outOfBoundsCase = nullptr) {
generateInBoundsCheck(
- xferOp, iv, builder, dim, /*resultTypes=*/TypeRange(),
+ b, xferOp, iv, dim, /*resultTypes=*/TypeRange(),
/*inBoundsCase=*/
- [&](OpBuilder &builder, Location loc) {
- inBoundsCase(builder, loc);
+ [&](OpBuilder &b, Location loc) {
+ inBoundsCase(b, loc);
return Value();
},
/*outOfBoundsCase=*/
- [&](OpBuilder &builder, Location loc) {
+ [&](OpBuilder &b, Location loc) {
if (outOfBoundsCase)
- outOfBoundsCase(builder, loc);
+ outOfBoundsCase(b, loc);
return Value();
});
}
/// Given an ArrayAttr, return a copy where the first element is dropped.
-static ArrayAttr dropFirstElem(OpBuilder &builder, ArrayAttr attr) {
+static ArrayAttr dropFirstElem(OpBuilder &b, ArrayAttr attr) {
if (!attr)
return attr;
- return ArrayAttr::get(builder.getContext(), attr.getValue().drop_front());
+ return ArrayAttr::get(b.getContext(), attr.getValue().drop_front());
}
/// Add the pass label to a vector transfer op if its rank is not the target
/// rank.
template <typename OpTy>
-static void maybeApplyPassLabel(OpBuilder &builder, OpTy newXferOp,
+static void maybeApplyPassLabel(OpBuilder &b, OpTy newXferOp,
unsigned targetRank) {
if (newXferOp.getVectorType().getRank() > targetRank)
- newXferOp->setAttr(kPassLabel, builder.getUnitAttr());
+ newXferOp->setAttr(kPassLabel, b.getUnitAttr());
}
namespace lowering_n_d {
@@ -249,8 +253,8 @@ struct BufferAllocs {
/// Allocate temporary buffers for data (vector) and mask (if present).
/// TODO: Parallelism and threadlocal considerations.
template <typename OpTy>
-static BufferAllocs allocBuffers(OpTy xferOp) {
- auto &b = ScopedContext::getBuilderRef();
+static BufferAllocs allocBuffers(OpBuilder &b, OpTy xferOp) {
+ Location loc = xferOp.getLoc();
OpBuilder::InsertionGuard guard(b);
Operation *scope =
xferOp->template getParentWithTrait<OpTrait::AutomaticAllocationScope>();
@@ -259,14 +263,14 @@ static BufferAllocs allocBuffers(OpTy xferOp) {
BufferAllocs result;
auto bufferType = MemRefType::get({}, xferOp.getVectorType());
- result.dataBuffer = memref_alloca(bufferType).value;
+ result.dataBuffer = b.create<memref::AllocaOp>(loc, bufferType);
if (xferOp.mask()) {
auto maskType = MemRefType::get({}, xferOp.mask().getType());
- auto maskBuffer = memref_alloca(maskType).value;
+ auto maskBuffer = b.create<memref::AllocaOp>(loc, maskType);
b.setInsertionPoint(xferOp);
- memref_store(xferOp.mask(), maskBuffer);
- result.maskBuffer = memref_load(maskBuffer);
+ b.create<memref::StoreOp>(loc, xferOp.mask(), maskBuffer);
+ result.maskBuffer = b.create<memref::LoadOp>(loc, maskBuffer);
}
return result;
@@ -359,7 +363,7 @@ struct Strategy<TransferReadOp> {
/// Note: The loop and type cast are generated in TransferOpConversion.
/// The original TransferReadOp and store op are deleted in `cleanup`.
/// Note: The `mask` operand is set in TransferOpConversion.
- static TransferReadOp rewriteOp(OpBuilder &builder,
+ static TransferReadOp rewriteOp(OpBuilder &b,
VectorTransferToSCFOptions options,
TransferReadOp xferOp, Value buffer,
Value iv) {
@@ -368,39 +372,36 @@ struct Strategy<TransferReadOp> {
storeIndices.push_back(iv);
SmallVector<Value, 8> xferIndices;
- getXferIndices(xferOp, iv, xferIndices);
+ getXferIndices(b, xferOp, iv, xferIndices);
+ Location loc = xferOp.getLoc();
auto bufferType = buffer.getType().dyn_cast<ShapedType>();
auto vecType = bufferType.getElementType().dyn_cast<VectorType>();
- auto inBoundsAttr = dropFirstElem(builder, xferOp.in_boundsAttr());
- auto newXfer =
- vector_transfer_read(
- vecType, xferOp.source(), xferIndices,
- AffineMapAttr::get(unpackedPermutationMap(xferOp, builder)),
- xferOp.padding(), Value(), inBoundsAttr)
- .value;
-
- maybeApplyPassLabel(builder,
- dyn_cast<TransferReadOp>(newXfer.getDefiningOp()),
- options.targetRank);
-
- memref_store(newXfer, buffer, storeIndices);
- return newXfer.getDefiningOp<TransferReadOp>();
+ auto inBoundsAttr = dropFirstElem(b, xferOp.in_boundsAttr());
+ auto newXferOp = b.create<vector::TransferReadOp>(
+ loc, vecType, xferOp.source(), xferIndices,
+ AffineMapAttr::get(unpackedPermutationMap(b, xferOp)), xferOp.padding(),
+ Value(), inBoundsAttr);
+
+ maybeApplyPassLabel(b, newXferOp, options.targetRank);
+
+ b.create<memref::StoreOp>(loc, newXferOp.vector(), buffer, storeIndices);
+ return newXferOp;
}
/// Handle out-of-bounds accesses on the to-be-unpacked dimension: Write
/// padding value to the temporary buffer.
- static void handleOutOfBoundsDim(OpBuilder & /*builder*/,
- TransferReadOp xferOp, Value buffer,
- Value iv) {
+ static void handleOutOfBoundsDim(OpBuilder &b, TransferReadOp xferOp,
+ Value buffer, Value iv) {
SmallVector<Value, 8> storeIndices;
getBufferIndices(xferOp, storeIndices);
storeIndices.push_back(iv);
+ Location loc = xferOp.getLoc();
auto bufferType = buffer.getType().dyn_cast<ShapedType>();
auto vecType = bufferType.getElementType().dyn_cast<VectorType>();
- auto vec = std_splat(vecType, xferOp.padding());
- memref_store(vec, buffer, storeIndices);
+ auto vec = b.create<SplatOp>(loc, vecType, xferOp.padding());
+ b.create<memref::StoreOp>(loc, vec, buffer, storeIndices);
}
/// Cleanup after rewriting the op.
@@ -443,7 +444,7 @@ struct Strategy<TransferWriteOp> {
/// to memory.
///
/// Note: For more details, see comments on Strategy<TransferReadOp>.
- static TransferWriteOp rewriteOp(OpBuilder &builder,
+ static TransferWriteOp rewriteOp(OpBuilder &b,
VectorTransferToSCFOptions options,
TransferWriteOp xferOp, Value buffer,
Value iv) {
@@ -452,22 +453,23 @@ struct Strategy<TransferWriteOp> {
loadIndices.push_back(iv);
SmallVector<Value, 8> xferIndices;
- getXferIndices(xferOp, iv, xferIndices);
-
- auto vec = memref_load(buffer, loadIndices);
- auto inBoundsAttr = dropFirstElem(builder, xferOp.in_boundsAttr());
- auto newXfer = vector_transfer_write(
- Type(), vec, xferOp.source(), xferIndices,
- AffineMapAttr::get(unpackedPermutationMap(xferOp, builder)), Value(),
+ getXferIndices(b, xferOp, iv, xferIndices);
+
+ Location loc = xferOp.getLoc();
+ auto vec = b.create<memref::LoadOp>(loc, buffer, loadIndices);
+ auto inBoundsAttr = dropFirstElem(b, xferOp.in_boundsAttr());
+ auto newXferOp = b.create<vector::TransferWriteOp>(
+ loc, Type(), vec, xferOp.source(), xferIndices,
+ AffineMapAttr::get(unpackedPermutationMap(b, xferOp)), Value(),
inBoundsAttr);
- maybeApplyPassLabel(builder, newXfer.op, options.targetRank);
+ maybeApplyPassLabel(b, newXferOp, options.targetRank);
- return newXfer;
+ return newXferOp;
}
/// Handle out-of-bounds accesses on the to-be-unpacked dimension.
- static void handleOutOfBoundsDim(OpBuilder &builder, TransferWriteOp xferOp,
+ static void handleOutOfBoundsDim(OpBuilder &b, TransferWriteOp xferOp,
Value buffer, Value iv) {}
/// Cleanup after rewriting the op.
@@ -518,8 +520,7 @@ struct PrepareTransferReadConversion
if (checkPrepareXferOp(xferOp, options).failed())
return failure();
- ScopedContext scope(rewriter, xferOp.getLoc());
- auto buffers = allocBuffers(xferOp);
+ auto buffers = allocBuffers(rewriter, xferOp);
auto *newXfer = rewriter.clone(*xferOp.getOperation());
newXfer->setAttr(kPassLabel, rewriter.getUnitAttr());
if (xferOp.mask()) {
@@ -527,7 +528,9 @@ struct PrepareTransferReadConversion
buffers.maskBuffer);
}
- memref_store(newXfer->getResult(0), buffers.dataBuffer);
+ Location loc = xferOp.getLoc();
+ rewriter.create<memref::StoreOp>(loc, newXfer->getResult(0),
+ buffers.dataBuffer);
rewriter.replaceOpWithNewOp<memref::LoadOp>(xferOp, buffers.dataBuffer);
return success();
@@ -566,10 +569,10 @@ struct PrepareTransferWriteConversion
if (checkPrepareXferOp(xferOp, options).failed())
return failure();
- ScopedContext scope(rewriter, xferOp.getLoc());
- auto buffers = allocBuffers(xferOp);
- memref_store(xferOp.vector(), buffers.dataBuffer);
- auto loadedVec = memref_load(buffers.dataBuffer);
+ Location loc = xferOp.getLoc();
+ auto buffers = allocBuffers(rewriter, xferOp);
+ rewriter.create<memref::StoreOp>(loc, xferOp.vector(), buffers.dataBuffer);
+ auto loadedVec = rewriter.create<memref::LoadOp>(loc, buffers.dataBuffer);
rewriter.updateRootInPlace(xferOp, [&]() {
xferOp.vectorMutable().assign(loadedVec);
xferOp->setAttr(kPassLabel, rewriter.getUnitAttr());
@@ -610,13 +613,13 @@ struct TransferOpConversion : public VectorToSCFPattern<OpTy> {
if (!xferOp->hasAttr(kPassLabel))
return failure();
- ScopedContext scope(rewriter, xferOp.getLoc());
-
// Find and cast data buffer. How the buffer can be found depends on OpTy.
+ ImplicitLocOpBuilder locB(xferOp.getLoc(), rewriter);
auto dataBuffer = Strategy<OpTy>::getBuffer(xferOp);
auto dataBufferType = dataBuffer.getType().template dyn_cast<MemRefType>();
auto castedDataType = unpackOneDim(dataBufferType);
- auto castedDataBuffer = vector_type_cast(castedDataType, dataBuffer);
+ auto castedDataBuffer =
+ locB.create<vector::TypeCastOp>(castedDataType, dataBuffer);
// If the xferOp has a mask: Find and cast mask buffer.
Value castedMaskBuffer;
@@ -633,26 +636,25 @@ struct TransferOpConversion : public VectorToSCFPattern<OpTy> {
castedMaskBuffer = maskBuffer;
} else {
auto castedMaskType = unpackOneDim(maskBufferType);
- castedMaskBuffer = vector_type_cast(castedMaskType, maskBuffer);
+ castedMaskBuffer =
+ locB.create<vector::TypeCastOp>(castedMaskType, maskBuffer);
}
}
// Loop bounds and step.
- auto lb = std_constant_index(0).value;
- auto ub = std_constant_index(
- castedDataType.getDimSize(castedDataType.getRank() - 1))
- .value;
- auto step = std_constant_index(1).value;
+ auto lb = locB.create<ConstantIndexOp>(0);
+ auto ub = locB.create<ConstantIndexOp>(
+ castedDataType.getDimSize(castedDataType.getRank() - 1));
+ auto step = locB.create<ConstantIndexOp>(1);
// Generate for loop.
- rewriter.create<scf::ForOp>(
- xferOp.getLoc(), lb, ub, step, ValueRange(),
+ locB.create<scf::ForOp>(
+ lb, ub, step, ValueRange(),
[&](OpBuilder &b, Location loc, Value iv, ValueRange /*loopState*/) {
- ScopedContext scope(b, loc);
generateInBoundsCheck(
- xferOp, iv, b, unpackedDim(xferOp),
+ b, xferOp, iv, unpackedDim(xferOp),
/*inBoundsCase=*/
- [&](OpBuilder &b, Location /*loc*/) {
+ [&](OpBuilder &b, Location loc) {
// Create new transfer op.
OpTy newXfer = Strategy<OpTy>::rewriteOp(
b, this->options, xferOp, castedDataBuffer, iv);
@@ -674,7 +676,8 @@ struct TransferOpConversion : public VectorToSCFPattern<OpTy> {
if (!xferOp.isBroadcastDim(0))
loadIndices.push_back(iv);
- auto mask = memref_load(castedMaskBuffer, loadIndices);
+ auto mask = b.create<memref::LoadOp>(loc, castedMaskBuffer,
+ loadIndices);
rewriter.updateRootInPlace(
newXfer, [&]() { newXfer.maskMutable().assign(mask); });
}
@@ -699,7 +702,7 @@ namespace lowering_n_d_unrolled {
/// If the original transfer op has a mask, compute the mask of the new transfer
/// op (for the current iteration `i`) and assign it.
template <typename OpTy>
-static void maybeAssignMask(OpBuilder &builder, OpTy xferOp, OpTy newXferOp,
+static void maybeAssignMask(OpBuilder &b, OpTy xferOp, OpTy newXferOp,
int64_t i) {
if (!xferOp.mask())
return;
@@ -713,11 +716,12 @@ static void maybeAssignMask(OpBuilder &builder, OpTy xferOp, OpTy newXferOp,
if (xferOp.getMaskType().getRank() > 1) {
// Unpack one dimension of the mask.
- OpBuilder::InsertionGuard guard(builder);
- builder.setInsertionPoint(newXferOp); // Insert load before newXfer.
+ OpBuilder::InsertionGuard guard(b);
+ b.setInsertionPoint(newXferOp); // Insert load before newXfer.
llvm::SmallVector<int64_t, 1> indices({i});
- auto newMask = vector_extract(xferOp.mask(), indices).value;
+ Location loc = xferOp.getLoc();
+ auto newMask = b.create<vector::ExtractOp>(loc, xferOp.mask(), indices);
newXferOp.maskMutable().assign(newMask);
}
@@ -764,7 +768,9 @@ struct UnrollTransferReadConversion
PatternRewriter &rewriter) const {
if (auto insertOp = getInsertOp(xferOp))
return insertOp.dest();
- return std_splat(xferOp.getVectorType(), xferOp.padding()).value;
+ Location loc = xferOp.getLoc();
+ return rewriter.create<SplatOp>(loc, xferOp.getVectorType(),
+ xferOp.padding());
}
/// If the result of the TransferReadOp has exactly one user, which is a
@@ -797,7 +803,6 @@ struct UnrollTransferReadConversion
if (xferOp.getVectorType().getRank() <= options.targetRank)
return failure();
- ScopedContext scope(rewriter, xferOp.getLoc());
auto insertOp = getInsertOp(xferOp);
auto vec = getResultVector(xferOp, rewriter);
auto vecType = vec.getType().dyn_cast<VectorType>();
@@ -807,18 +812,17 @@ struct UnrollTransferReadConversion
int64_t dimSize = xferVecType.getShape()[0];
// Generate fully unrolled loop of transfer ops.
+ Location loc = xferOp.getLoc();
for (int64_t i = 0; i < dimSize; ++i) {
- Value iv = std_constant_index(i);
+ Value iv = rewriter.create<ConstantIndexOp>(loc, i);
vec = generateInBoundsCheck(
- xferOp, iv, rewriter, unpackedDim(xferOp), TypeRange(vecType),
+ rewriter, xferOp, iv, unpackedDim(xferOp), TypeRange(vecType),
/*inBoundsCase=*/
[&](OpBuilder &b, Location loc) {
- ScopedContext scope(b, loc);
-
// Indices for the new transfer op.
SmallVector<Value, 8> xferIndices;
- getXferIndices(xferOp, iv, xferIndices);
+ getXferIndices(b, xferOp, iv, xferIndices);
// Indices for the new vector.insert op.
SmallVector<int64_t, 8> insertionIndices;
@@ -826,18 +830,13 @@ struct UnrollTransferReadConversion
insertionIndices.push_back(i);
auto inBoundsAttr = dropFirstElem(b, xferOp.in_boundsAttr());
- auto newXferOpVal =
- vector_transfer_read(
- newXferVecType, xferOp.source(), xferIndices,
- AffineMapAttr::get(unpackedPermutationMap(xferOp, b)),
- xferOp.padding(), Value(), inBoundsAttr)
- .value;
- auto newXferOp =
- dyn_cast<TransferReadOp>(newXferOpVal.getDefiningOp());
-
+ auto newXferOp = b.create<vector::TransferReadOp>(
+ loc, newXferVecType, xferOp.source(), xferIndices,
+ AffineMapAttr::get(unpackedPermutationMap(b, xferOp)),
+ xferOp.padding(), Value(), inBoundsAttr);
maybeAssignMask(b, xferOp, newXferOp, i);
-
- return vector_insert(newXferOp, vec, insertionIndices).value;
+ return b.create<vector::InsertOp>(loc, newXferOp, vec,
+ insertionIndices);
},
/*outOfBoundsCase=*/
[&](OpBuilder &b, Location loc) {
@@ -920,38 +919,35 @@ struct UnrollTransferWriteConversion
if (xferOp.getVectorType().getRank() <= options.targetRank)
return failure();
- ScopedContext scope(rewriter, xferOp.getLoc());
auto vec = getDataVector(xferOp);
auto xferVecType = xferOp.getVectorType();
int64_t dimSize = xferVecType.getShape()[0];
// Generate fully unrolled loop of transfer ops.
+ Location loc = xferOp.getLoc();
for (int64_t i = 0; i < dimSize; ++i) {
- Value iv = std_constant_index(i);
+ Value iv = rewriter.create<ConstantIndexOp>(loc, i);
generateInBoundsCheck(
- xferOp, iv, rewriter, unpackedDim(xferOp),
+ rewriter, xferOp, iv, unpackedDim(xferOp),
/*inBoundsCase=*/[&](OpBuilder &b, Location loc) {
- ScopedContext scope(b, loc);
-
// Indices for the new transfer op.
SmallVector<Value, 8> xferIndices;
- getXferIndices(xferOp, iv, xferIndices);
+ getXferIndices(b, xferOp, iv, xferIndices);
// Indices for the new vector.extract op.
SmallVector<int64_t, 8> extractionIndices;
getExtractionIndices(xferOp, extractionIndices);
extractionIndices.push_back(i);
- auto extracted = vector_extract(vec, extractionIndices).value;
+ auto extracted =
+ b.create<vector::ExtractOp>(loc, vec, extractionIndices);
auto inBoundsAttr = dropFirstElem(b, xferOp.in_boundsAttr());
- auto newXferOp =
- vector_transfer_write(
- Type(), extracted, xferOp.source(), xferIndices,
- AffineMapAttr::get(unpackedPermutationMap(xferOp, b)),
- Value(), inBoundsAttr)
- .op;
+ auto newXferOp = b.create<vector::TransferWriteOp>(
+ loc, Type(), extracted, xferOp.source(), xferIndices,
+ AffineMapAttr::get(unpackedPermutationMap(b, xferOp)), Value(),
+ inBoundsAttr);
maybeAssignMask(b, xferOp, newXferOp, i);
});
@@ -971,7 +967,7 @@ namespace lowering_1_d {
/// the transfer is operating. A return value of None indicates a broadcast.
template <typename OpTy>
static Optional<int64_t>
-get1dMemrefIndices(OpTy xferOp, Value iv,
+get1dMemrefIndices(OpBuilder &b, OpTy xferOp, Value iv,
SmallVector<Value, 8> &memrefIndices) {
auto indices = xferOp.indices();
auto map = xferOp.permutation_map();
@@ -980,9 +976,12 @@ get1dMemrefIndices(OpTy xferOp, Value iv,
assert(map.getNumResults() == 1 &&
"Expected 1 permutation map result for 1D transfer");
if (auto expr = map.getResult(0).template dyn_cast<AffineDimExpr>()) {
+ Location loc = xferOp.getLoc();
auto dim = expr.getPosition();
- using edsc::op::operator+;
- memrefIndices[dim] = memrefIndices[dim] + iv;
+ AffineExpr d0, d1;
+ bindDims(xferOp.getContext(), d0, d1);
+ Value offset = memrefIndices[dim];
+ memrefIndices[dim] = makeComposedAffineApply(b, loc, d0 + d1, {offset, iv});
return dim;
}
@@ -999,55 +998,61 @@ struct Strategy1d;
/// Codegen strategy for TransferReadOp.
template <>
struct Strategy1d<TransferReadOp> {
- static void generateForLoopBody(OpBuilder &builder, Location loc,
+ static void generateForLoopBody(OpBuilder &b, Location loc,
TransferReadOp xferOp, Value iv,
ValueRange loopState) {
SmallVector<Value, 8> indices;
- auto dim = get1dMemrefIndices(xferOp, iv, indices);
- auto ivI32 = std_index_cast(IntegerType::get(builder.getContext(), 32), iv);
+ auto dim = get1dMemrefIndices(b, xferOp, iv, indices);
+ Value ivI32 =
+ b.create<IndexCastOp>(loc, IntegerType::get(b.getContext(), 32), iv);
auto vec = loopState[0];
// In case of out-of-bounds access, leave `vec` as is (was initialized with
// padding value).
auto nextVec = generateInBoundsCheck(
- xferOp, iv, builder, dim, TypeRange(xferOp.getVectorType()),
+ b, xferOp, iv, dim, TypeRange(xferOp.getVectorType()),
/*inBoundsCase=*/
- [&](OpBuilder & /*b*/, Location loc) {
- auto val = memref_load(xferOp.source(), indices);
- return vector_insert_element(val, vec, ivI32.value).value;
+ [&](OpBuilder &b, Location loc) {
+ Value val = b.create<memref::LoadOp>(loc, xferOp.source(), indices);
+ return b.create<vector::InsertElementOp>(loc, val, vec, ivI32);
},
/*outOfBoundsCase=*/
[&](OpBuilder & /*b*/, Location loc) { return vec; });
- builder.create<scf::YieldOp>(loc, nextVec);
+ b.create<scf::YieldOp>(loc, nextVec);
}
- static Value initialLoopState(TransferReadOp xferOp) {
+ static Value initialLoopState(OpBuilder &b, TransferReadOp xferOp) {
// Inititalize vector with padding value.
- return std_splat(xferOp.getVectorType(), xferOp.padding()).value;
+ Location loc = xferOp.getLoc();
+ return b.create<SplatOp>(loc, xferOp.getVectorType(), xferOp.padding());
}
};
/// Codegen strategy for TransferWriteOp.
template <>
struct Strategy1d<TransferWriteOp> {
- static void generateForLoopBody(OpBuilder &builder, Location loc,
+ static void generateForLoopBody(OpBuilder &b, Location loc,
TransferWriteOp xferOp, Value iv,
ValueRange /*loopState*/) {
SmallVector<Value, 8> indices;
- auto dim = get1dMemrefIndices(xferOp, iv, indices);
- auto ivI32 = std_index_cast(IntegerType::get(builder.getContext(), 32), iv);
+ auto dim = get1dMemrefIndices(b, xferOp, iv, indices);
+ Value ivI32 =
+ b.create<IndexCastOp>(loc, IntegerType::get(b.getContext(), 32), iv);
// Nothing to do in case of out-of-bounds access.
generateInBoundsCheck(
- xferOp, iv, builder, dim,
- /*inBoundsCase=*/[&](OpBuilder & /*b*/, Location loc) {
- auto val = vector_extract_element(xferOp.vector(), ivI32.value);
- memref_store(val, xferOp.source(), indices);
+ b, xferOp, iv, dim,
+ /*inBoundsCase=*/[&](OpBuilder &b, Location loc) {
+ auto val =
+ b.create<vector::ExtractElementOp>(loc, xferOp.vector(), ivI32);
+ b.create<memref::StoreOp>(loc, val, xferOp.source(), indices);
});
- builder.create<scf::YieldOp>(loc);
+ b.create<scf::YieldOp>(loc);
}
- static Value initialLoopState(TransferWriteOp xferOp) { return Value(); }
+ static Value initialLoopState(OpBuilder &b, TransferWriteOp xferOp) {
+ return Value();
+ }
};
/// Return true if the last dimension of the MemRefType has unit stride.
@@ -1095,7 +1100,6 @@ struct TransferOp1dConversion : public VectorToSCFPattern<OpTy> {
LogicalResult matchAndRewrite(OpTy xferOp,
PatternRewriter &rewriter) const override {
- ScopedContext scope(rewriter, xferOp.getLoc());
auto map = xferOp.permutation_map();
auto memRefType = xferOp.getShapedType().template dyn_cast<MemRefType>();
@@ -1107,19 +1111,18 @@ struct TransferOp1dConversion : public VectorToSCFPattern<OpTy> {
return failure(); // Handled by ConvertVectorToLLVM
// Loop bounds, step, state...
+ Location loc = xferOp.getLoc();
auto vecType = xferOp.getVectorType();
- auto lb = std_constant_index(0);
- auto ub = std_constant_index(vecType.getDimSize(0));
- auto step = std_constant_index(1);
- auto loopState = Strategy1d<OpTy>::initialLoopState(xferOp);
+ auto lb = rewriter.create<ConstantIndexOp>(loc, 0);
+ auto ub = rewriter.create<ConstantIndexOp>(loc, vecType.getDimSize(0));
+ auto step = rewriter.create<ConstantIndexOp>(loc, 1);
+ auto loopState = Strategy1d<OpTy>::initialLoopState(rewriter, xferOp);
// Generate for loop.
rewriter.replaceOpWithNewOp<scf::ForOp>(
xferOp, lb, ub, step, loopState ? ValueRange(loopState) : ValueRange(),
- [&](OpBuilder &builder, Location loc, Value iv, ValueRange loopState) {
- ScopedContext nestedScope(builder, loc);
- Strategy1d<OpTy>::generateForLoopBody(builder, loc, xferOp, iv,
- loopState);
+ [&](OpBuilder &b, Location loc, Value iv, ValueRange loopState) {
+ Strategy1d<OpTy>::generateForLoopBody(b, loc, xferOp, iv, loopState);
});
return success();
diff --git a/mlir/lib/Dialect/Affine/IR/AffineOps.cpp b/mlir/lib/Dialect/Affine/IR/AffineOps.cpp
index 6063bb5d835d..b267223b423e 100644
--- a/mlir/lib/Dialect/Affine/IR/AffineOps.cpp
+++ b/mlir/lib/Dialect/Affine/IR/AffineOps.cpp
@@ -698,7 +698,7 @@ void mlir::fullyComposeAffineMapAndOperands(AffineMap *map,
AffineApplyOp mlir::makeComposedAffineApply(OpBuilder &b, Location loc,
AffineMap map,
- ArrayRef<Value> operands) {
+ ValueRange operands) {
AffineMap normalizedMap = map;
SmallVector<Value, 8> normalizedOperands(operands.begin(), operands.end());
composeAffineMapAndOperands(&normalizedMap, &normalizedOperands);
@@ -706,6 +706,13 @@ AffineApplyOp mlir::makeComposedAffineApply(OpBuilder &b, Location loc,
return b.create<AffineApplyOp>(loc, normalizedMap, normalizedOperands);
}
+AffineApplyOp mlir::makeComposedAffineApply(OpBuilder &b, Location loc,
+ AffineExpr e, ValueRange values) {
+ return makeComposedAffineApply(
+ b, loc, AffineMap::inferFromExprList(ArrayRef<AffineExpr>{e}).front(),
+ values);
+}
+
// A symbol may appear as a dim in affine.apply operations. This function
// canonicalizes dims that are valid symbols into actual symbols.
template <class MapOrSet>
diff --git a/mlir/lib/Dialect/Linalg/Transforms/Interchange.cpp b/mlir/lib/Dialect/Linalg/Transforms/Interchange.cpp
index e03d8cb01bc1..842fccfda218 100644
--- a/mlir/lib/Dialect/Linalg/Transforms/Interchange.cpp
+++ b/mlir/lib/Dialect/Linalg/Transforms/Interchange.cpp
@@ -16,7 +16,6 @@
#include "mlir/Dialect/Linalg/Utils/Utils.h"
#include "mlir/Dialect/StandardOps/EDSC/Intrinsics.h"
#include "mlir/Dialect/Utils/StructuredOpsUtils.h"
-#include "mlir/Dialect/Vector/EDSC/Intrinsics.h"
#include "mlir/Dialect/Vector/VectorOps.h"
#include "mlir/IR/AffineExpr.h"
#include "mlir/IR/Matchers.h"
diff --git a/mlir/lib/Dialect/Linalg/Transforms/Transforms.cpp b/mlir/lib/Dialect/Linalg/Transforms/Transforms.cpp
index 736d298a713a..f0ea4e8423a5 100644
--- a/mlir/lib/Dialect/Linalg/Transforms/Transforms.cpp
+++ b/mlir/lib/Dialect/Linalg/Transforms/Transforms.cpp
@@ -18,7 +18,6 @@
#include "mlir/Dialect/Linalg/Utils/Utils.h"
#include "mlir/Dialect/StandardOps/EDSC/Intrinsics.h"
#include "mlir/Dialect/Utils/StructuredOpsUtils.h"
-#include "mlir/Dialect/Vector/EDSC/Intrinsics.h"
#include "mlir/Dialect/Vector/VectorOps.h"
#include "mlir/IR/AffineExpr.h"
#include "mlir/IR/Matchers.h"
diff --git a/mlir/lib/Dialect/Linalg/Transforms/Vectorization.cpp b/mlir/lib/Dialect/Linalg/Transforms/Vectorization.cpp
index aee5233f4930..5ceb56868a17 100644
--- a/mlir/lib/Dialect/Linalg/Transforms/Vectorization.cpp
+++ b/mlir/lib/Dialect/Linalg/Transforms/Vectorization.cpp
@@ -17,7 +17,6 @@
#include "mlir/Dialect/Linalg/Utils/Utils.h"
#include "mlir/Dialect/StandardOps/EDSC/Intrinsics.h"
#include "mlir/Dialect/Utils/StructuredOpsUtils.h"
-#include "mlir/Dialect/Vector/EDSC/Intrinsics.h"
#include "mlir/Dialect/Vector/VectorOps.h"
#include "mlir/IR/AffineExpr.h"
#include "mlir/IR/Matchers.h"
@@ -158,7 +157,7 @@ static Operation *getSingleBinaryOpAssumedReduction(OpOperand &outputOperand) {
/// Otherwise, just return `value`.
// TODO: this is best effort atm and there is currently no guarantee of
// correctness for the broadcast semantics.
-static Value broadcastIfNeeded(OpBuilder &builder, Value value,
+static Value broadcastIfNeeded(OpBuilder &b, Value value,
ArrayRef<int64_t> shape) {
unsigned numDimsGtOne = std::count_if(shape.begin(), shape.end(),
[](int64_t val) { return val > 1; });
@@ -169,8 +168,8 @@ static Value broadcastIfNeeded(OpBuilder &builder, Value value,
return value;
auto newVecType = VectorType::get(shape, vecType ? vecType.getElementType()
: value.getType());
- return builder.create<vector::BroadcastOp>(
- builder.getInsertionPoint()->getLoc(), newVecType, value);
+ return b.create<vector::BroadcastOp>(b.getInsertionPoint()->getLoc(),
+ newVecType, value);
}
static llvm::Optional<vector::CombiningKind>
@@ -189,7 +188,7 @@ getKindForOp(Operation *reductionOp) {
/// If value of assumed VectorType has a shape
diff erent than `shape`, build and
/// return a new vector.broadcast to `shape`.
/// Otherwise, just return value.
-static Value reduceIfNeeded(OpBuilder &builder, VectorType targetVectorType,
+static Value reduceIfNeeded(OpBuilder &b, VectorType targetVectorType,
Value value, OpOperand &outputOperand) {
assert(targetVectorType.getShape() ==
outputOperand.get().getType().cast<ShapedType>().getShape());
@@ -201,7 +200,7 @@ static Value reduceIfNeeded(OpBuilder &builder, VectorType targetVectorType,
Operation *reductionOp = getSingleBinaryOpAssumedReduction(outputOperand);
auto linalgOp = cast<LinalgOp>(outputOperand.getOwner());
unsigned pos = 0;
- MLIRContext *ctx = builder.getContext();
+ MLIRContext *ctx = b.getContext();
SmallVector<AffineExpr> exprs;
for (auto s : linalgOp.iterator_types())
if (isParallelIterator(s))
@@ -217,41 +216,45 @@ static Value reduceIfNeeded(OpBuilder &builder, VectorType targetVectorType,
reductionMask[idx] = true;
++idx;
}
- return builder.create<vector::MultiDimReductionOp>(loc, value, reductionMask,
- *maybeKind);
+ return b.create<vector::MultiDimReductionOp>(loc, value, reductionMask,
+ *maybeKind);
}
/// Build a vector.transfer_read from `source` at indices set to all `0`.
/// If source has rank zero, build an memref.load.
/// Return the produced value.
-static Value buildVectorRead(OpBuilder &builder, Value source,
- VectorType vectorType, AffineMap map) {
- edsc::ScopedContext scope(builder);
+static Value buildVectorRead(OpBuilder &b, Value source, VectorType vectorType,
+ AffineMap map) {
+ Location loc = source.getLoc();
auto shapedType = source.getType().cast<ShapedType>();
- SmallVector<Value> indices(shapedType.getRank(), std_constant_index(0));
- return vector_transfer_read(vectorType, source, indices, map);
+ SmallVector<Value> indices(shapedType.getRank(),
+ b.create<ConstantIndexOp>(loc, 0));
+ return b.create<vector::TransferReadOp>(loc, vectorType, source, indices,
+ map);
}
/// Build a vector.transfer_write of `value` into `outputOperand` at indices set
/// to all `0`; where `outputOperand` is an output operand of the LinalgOp
/// currently being vectorized. If `dest` has null rank, build an memref.store.
/// Return the produced value or null if no value is produced.
-static Value buildVectorWrite(OpBuilder &builder, Value value,
+static Value buildVectorWrite(OpBuilder &b, Value value,
OpOperand &outputOperand) {
- edsc::ScopedContext scope(builder);
Operation *write;
+ Location loc = value.getLoc();
auto shapedType = outputOperand.get().getType().cast<ShapedType>();
if (VectorType vectorType =
extractVectorTypeFromShapedValue(outputOperand.get())) {
auto linalgOp = cast<LinalgOp>(outputOperand.getOwner());
AffineMap map = reindexIndexingMap(
linalgOp.getIndexingMap(outputOperand.getOperandNumber()));
- SmallVector<Value> indices(shapedType.getRank(), std_constant_index(0));
- value = broadcastIfNeeded(builder, value, vectorType.getShape());
- value = reduceIfNeeded(builder, vectorType, value, outputOperand);
- write = vector_transfer_write(value, outputOperand.get(), indices, map);
+ SmallVector<Value> indices(shapedType.getRank(),
+ b.create<ConstantIndexOp>(loc, 0));
+ value = broadcastIfNeeded(b, value, vectorType.getShape());
+ value = reduceIfNeeded(b, vectorType, value, outputOperand);
+ write = b.create<vector::TransferWriteOp>(loc, value, outputOperand.get(),
+ indices, map);
} else {
- write = memref_store(value, outputOperand.get());
+ write = b.create<memref::StoreOp>(loc, value, outputOperand.get());
}
LLVM_DEBUG(dbgs() << "\n[" DEBUG_TYPE "]: vectorized op: " << *write);
if (!write->getResults().empty())
@@ -273,7 +276,7 @@ using CustomVectorizationHook = std::function<VectorizationResult(
/// vectorization algorithm for RAUW. This function is meant to be used as a
/// CustomVectorizationHook.
static VectorizationResult
-vectorizeLinalgYield(OpBuilder &builder, Operation *op,
+vectorizeLinalgYield(OpBuilder &b, Operation *op,
const BlockAndValueMapping &bvm, LinalgOp linalgOp,
SmallVectorImpl<Value> &newResults) {
auto yieldOp = dyn_cast<linalg::YieldOp>(op);
@@ -284,7 +287,7 @@ vectorizeLinalgYield(OpBuilder &builder, Operation *op,
// TODO: use a map.
Value vectorValue = bvm.lookup(outputs.value());
Value newResult = buildVectorWrite(
- builder, vectorValue, linalgOp.getOutputOpOperands()[outputs.index()]);
+ b, vectorValue, linalgOp.getOutputOpOperands()[outputs.index()]);
if (newResult)
newResults.push_back(newResult);
}
@@ -295,8 +298,8 @@ vectorizeLinalgYield(OpBuilder &builder, Operation *op,
/// VectorizationStatus::NewOp to signal the vectorization algorithm that it
/// should map the produced operations. This function is meant to be used as a
/// CustomVectorizationHook.
-static VectorizationResult
-vectorizeLinalgIndex(OpBuilder &builder, Operation *op, LinalgOp linalgOp) {
+static VectorizationResult vectorizeLinalgIndex(OpBuilder &b, Operation *op,
+ LinalgOp linalgOp) {
IndexOp indexOp = dyn_cast<linalg::IndexOp>(op);
if (!indexOp)
return VectorizationResult{VectorizationStatus::Failure, nullptr};
@@ -307,7 +310,7 @@ vectorizeLinalgIndex(OpBuilder &builder, Operation *op, LinalgOp linalgOp) {
SmallVector<int64_t> constantSeq(
llvm::seq<int64_t>(0, targetShape[indexOp.dim()]));
ConstantOp constantOp =
- builder.create<ConstantOp>(loc, builder.getIndexVectorAttr(constantSeq));
+ b.create<ConstantOp>(loc, b.getIndexVectorAttr(constantSeq));
// Return the one-dimensional index vector if it lives in the trailing
// dimension of the iteration space since the vectorization algorithm in this
// case can handle the broadcast.
@@ -317,13 +320,13 @@ vectorizeLinalgIndex(OpBuilder &builder, Operation *op, LinalgOp linalgOp) {
// broadcast the one-dimensional index vector to the permuted shape, and
// finally transpose the broadcasted index vector to undo the permutation.
std::swap(targetShape[indexOp.dim()], targetShape.back());
- auto broadCastOp = builder.create<vector::BroadcastOp>(
- loc, VectorType::get(targetShape, builder.getIndexType()), constantOp);
+ auto broadCastOp = b.create<vector::BroadcastOp>(
+ loc, VectorType::get(targetShape, b.getIndexType()), constantOp);
SmallVector<int64_t> transposition(
llvm::seq<int64_t>(0, linalgOp.getNumLoops()));
std::swap(transposition.back(), transposition[indexOp.dim()]);
auto transposeOp =
- builder.create<vector::TransposeOp>(loc, broadCastOp, transposition);
+ b.create<vector::TransposeOp>(loc, broadCastOp, transposition);
return VectorizationResult{VectorizationStatus::NewOp, transposeOp};
}
@@ -347,8 +350,7 @@ vectorizeLinalgIndex(OpBuilder &builder, Operation *op, LinalgOp linalgOp) {
/// This function does not update `bvm` but returns a VectorizationStatus that
/// instructs the caller what `bvm` update needs to occur.
static VectorizationResult
-vectorizeOneOp(OpBuilder &builder, Operation *op,
- const BlockAndValueMapping &bvm,
+vectorizeOneOp(OpBuilder &b, Operation *op, const BlockAndValueMapping &bvm,
ArrayRef<CustomVectorizationHook> customVectorizationHooks) {
LLVM_DEBUG(dbgs() << "\n[" DEBUG_TYPE "]: vectorize op " << *op);
@@ -365,7 +367,7 @@ vectorizeOneOp(OpBuilder &builder, Operation *op,
// 2. Constant ops don't get vectorized but rather broadcasted at their users.
// Clone so that the constant is not confined to the linalgOp block .
if (isa<ConstantOp>(op))
- return VectorizationResult{VectorizationStatus::NewOp, builder.clone(*op)};
+ return VectorizationResult{VectorizationStatus::NewOp, b.clone(*op)};
// 3. Only ElementwiseMappable are allowed in the generic vectorization.
if (!OpTrait::hasElementwiseMappableTraits(op))
@@ -383,7 +385,7 @@ vectorizeOneOp(OpBuilder &builder, Operation *op,
auto vectorizedOperands = llvm::map_range(op->getOperands(), [&](Value v) {
return firstMaxRankedShape.empty()
? bvm.lookup(v)
- : broadcastIfNeeded(builder, bvm.lookup(v), firstMaxRankedShape);
+ : broadcastIfNeeded(b, bvm.lookup(v), firstMaxRankedShape);
});
// c. for elementwise, the result is the vector with the firstMaxRankedShape
auto returnTypes = llvm::map_range(op->getResultTypes(), [&](Type t) {
@@ -398,7 +400,7 @@ vectorizeOneOp(OpBuilder &builder, Operation *op,
state.addOperands(llvm::to_vector<4>(vectorizedOperands));
state.addTypes(llvm::to_vector<4>(returnTypes));
return VectorizationResult{VectorizationStatus::NewOp,
- builder.createOperation(state)};
+ b.createOperation(state)};
}
/// Detect whether `r` has only ConstantOp, ElementwiseMappable and YieldOp.
@@ -455,7 +457,7 @@ static bool isElementwise(Operation *op) {
/// This is not deemed a problem as we expect canonicalizations and foldings to
/// aggressively clean up the useless work.
LogicalResult vectorizeAsLinalgGeneric(
- OpBuilder &builder, LinalgOp linalgOp, SmallVectorImpl<Value> &newResults,
+ OpBuilder &b, LinalgOp linalgOp, SmallVectorImpl<Value> &newResults,
bool broadcastToMaximalCommonShape = false,
ArrayRef<CustomVectorizationHook> customVectorizationHooks = {}) {
// 1. Fail to vectorize if the operation does not have one non-empty region.
@@ -485,8 +487,7 @@ LogicalResult vectorizeAsLinalgGeneric(
ShapedType shapedType = shapedArg.getType().cast<ShapedType>();
// TODO: 0-d vectors.
if (shapedType.getShape().empty()) {
- Value loaded =
- builder.create<memref::LoadOp>(linalgOp.getLoc(), shapedArg);
+ Value loaded = b.create<memref::LoadOp>(linalgOp.getLoc(), shapedArg);
LLVM_DEBUG(dbgs() << "\n[" DEBUG_TYPE "]: new vectorized bbarg("
<< bbarg.getArgNumber() << "): " << loaded);
bvm.map(bbarg, loaded);
@@ -506,7 +507,7 @@ LogicalResult vectorizeAsLinalgGeneric(
vectorType = VectorType::get(map.compose(shapedType.getShape()),
shapedType.getElementType());
}
- Value vectorRead = buildVectorRead(builder, shapedArg, vectorType, map);
+ Value vectorRead = buildVectorRead(b, shapedArg, vectorType, map);
LLVM_DEBUG(dbgs() << "\n[" DEBUG_TYPE "]: new vectorized bbarg("
<< bbarg.getArgNumber() << "): " << vectorRead);
bvm.map(bbarg, vectorRead);
@@ -518,7 +519,7 @@ LogicalResult vectorizeAsLinalgGeneric(
CustomVectorizationHook vectorizeYield =
[&](Operation *op,
const BlockAndValueMapping &bvm) -> VectorizationResult {
- return vectorizeLinalgYield(builder, op, bvm, linalgOp, newResults);
+ return vectorizeLinalgYield(b, op, bvm, linalgOp, newResults);
};
hooks.push_back(vectorizeYield);
@@ -526,13 +527,13 @@ LogicalResult vectorizeAsLinalgGeneric(
CustomVectorizationHook vectorizeIndex =
[&](Operation *op,
const BlockAndValueMapping &bvm) -> VectorizationResult {
- return vectorizeLinalgIndex(builder, op, linalgOp);
+ return vectorizeLinalgIndex(b, op, linalgOp);
};
hooks.push_back(vectorizeIndex);
// 5. Iteratively call `vectorizeOneOp` to each op in the slice.
for (Operation &op : block.getOperations()) {
- VectorizationResult result = vectorizeOneOp(builder, &op, bvm, hooks);
+ VectorizationResult result = vectorizeOneOp(b, &op, bvm, hooks);
if (result.status == VectorizationStatus::Failure) {
LLVM_DEBUG(dbgs() << "\n[" DEBUG_TYPE "]: failed to vectorize: " << op);
return failure();
@@ -547,7 +548,7 @@ LogicalResult vectorizeAsLinalgGeneric(
return success();
}
-static LogicalResult vectorizeContraction(OpBuilder &builder, LinalgOp linalgOp,
+static LogicalResult vectorizeContraction(OpBuilder &b, LinalgOp linalgOp,
SmallVectorImpl<Value> &newResults) {
assert(isaContractionOpInterface(linalgOp) &&
"expected vectorizeContraction preconditions to be met");
@@ -568,8 +569,7 @@ static LogicalResult vectorizeContraction(OpBuilder &builder, LinalgOp linalgOp,
auto vType = outShape.empty()
? op->getResult(0).getType()
: VectorType::get(outShape, op->getResult(0).getType());
- auto zero =
- builder.create<ConstantOp>(loc, vType, builder.getZeroAttr(vType));
+ auto zero = b.create<ConstantOp>(loc, vType, b.getZeroAttr(vType));
// Indexing maps at the time of vector.transfer_read are adjusted to order
// vector dimensions in the same order as the canonical linalg op iteration
// space order.
@@ -584,12 +584,12 @@ static LogicalResult vectorizeContraction(OpBuilder &builder, LinalgOp linalgOp,
.compose(linalgOp.getIndexingMap(1)),
inversePermutation(reindexIndexingMap(linalgOp.getIndexingMap(2)))
.compose(linalgOp.getIndexingMap(2))};
- Operation *contract = builder.create<vector::ContractionOp>(
+ Operation *contract = b.create<vector::ContractionOp>(
loc, bvm.lookup(op->getOperand(0)), bvm.lookup(op->getOperand(1)), zero,
- builder.getAffineMapArrayAttr(indexingMaps), linalgOp.iterator_types());
+ b.getAffineMapArrayAttr(indexingMaps), linalgOp.iterator_types());
return VectorizationResult{VectorizationStatus::NewOp, contract};
};
- return vectorizeAsLinalgGeneric(builder, linalgOp, newResults,
+ return vectorizeAsLinalgGeneric(b, linalgOp, newResults,
/*broadcastToMaximalCommonShape=*/false,
{vectorizeContraction});
}
@@ -635,22 +635,22 @@ LogicalResult mlir::linalg::vectorizeLinalgOpPrecondition(Operation *op) {
}
LogicalResult
-mlir::linalg::vectorizeLinalgOp(OpBuilder &builder, Operation *op,
+mlir::linalg::vectorizeLinalgOp(OpBuilder &b, Operation *op,
SmallVectorImpl<Value> &newResults) {
if (failed(vectorizeLinalgOpPrecondition(op)))
return failure();
- edsc::ScopedContext scope(builder, op->getLoc());
+ edsc::ScopedContext scope(b, op->getLoc());
auto linalgOp = cast<LinalgOp>(op);
if (isaContractionOpInterface(linalgOp))
- return vectorizeContraction(builder, linalgOp, newResults);
+ return vectorizeContraction(b, linalgOp, newResults);
LLVM_DEBUG(dbgs() << "\n[" DEBUG_TYPE "]: "
<< "Vectorize linalg op as a generic by broadcasting to "
"maximal common shape: "
<< *op);
- return vectorizeAsLinalgGeneric(builder, linalgOp, newResults,
+ return vectorizeAsLinalgGeneric(b, linalgOp, newResults,
/*broadcastToMaximalCommonShape=*/true);
}
@@ -762,13 +762,16 @@ LogicalResult ConvOpVectorization<ConvOp, N>::matchAndRewrite(
Type elemType = inShapeType.getElementType();
auto map = AffineMap::get(rank, 0, mapping, context);
- SmallVector<Value, 4> zeros(rank, std_constant_index(0));
+ SmallVector<Value, 4> zeros(rank, rewriter.create<ConstantIndexOp>(loc, 0));
auto vecType = VectorType::get(vectorDims, elemType);
- auto inputVec = vector_transfer_read(vecType, input, zeros, map);
- auto kernelVec = vector_transfer_read(vecType, kernel, zeros, map);
+ auto inputVec =
+ rewriter.create<vector::TransferReadOp>(loc, vecType, input, zeros, map);
+ auto kernelVec =
+ rewriter.create<vector::TransferReadOp>(loc, vecType, kernel, zeros, map);
- auto acc = std_constant(elemType, rewriter.getZeroAttr(elemType));
+ auto acc = rewriter.create<ConstantOp>(loc, elemType,
+ rewriter.getZeroAttr(elemType));
std::array<AffineMap, 3> indexingMaps{
AffineMap::getMultiDimIdentityMap(numDims, context),
diff --git a/mlir/lib/Dialect/Vector/CMakeLists.txt b/mlir/lib/Dialect/Vector/CMakeLists.txt
index b74c9a5a823a..9ea8aabb698d 100644
--- a/mlir/lib/Dialect/Vector/CMakeLists.txt
+++ b/mlir/lib/Dialect/Vector/CMakeLists.txt
@@ -3,7 +3,6 @@ add_mlir_dialect_library(MLIRVector
VectorTransferOpTransforms.cpp
VectorTransforms.cpp
VectorUtils.cpp
- EDSC/Builders.cpp
ADDITIONAL_HEADER_DIRS
${MLIR_MAIN_INCLUDE_DIR}/mlir/Dialect/Vector
@@ -13,12 +12,11 @@ add_mlir_dialect_library(MLIRVector
MLIRVectorOpsEnumsIncGen
LINK_LIBS PUBLIC
- MLIRAffineEDSC
- MLIREDSC
MLIRDialectUtils
MLIRIR
MLIRStandard
MLIRAffine
+ MLIRAffineUtils
MLIRLinalg
MLIRMemRef
MLIRSCF
diff --git a/mlir/lib/Dialect/Vector/EDSC/Builders.cpp b/mlir/lib/Dialect/Vector/EDSC/Builders.cpp
deleted file mode 100644
index 7d6d2b9432d7..000000000000
--- a/mlir/lib/Dialect/Vector/EDSC/Builders.cpp
+++ /dev/null
@@ -1,40 +0,0 @@
-//===- Builders.cpp - MLIR Declarative Linalg Builders --------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "mlir/Dialect/Vector/EDSC/Builders.h"
-#include "mlir/Dialect/Vector/EDSC/Intrinsics.h"
-#include "mlir/Dialect/Vector/VectorOps.h"
-#include "mlir/EDSC/Builders.h"
-#include "mlir/IR/AffineExpr.h"
-#include "mlir/IR/Builders.h"
-
-using namespace mlir;
-using namespace mlir::edsc;
-using namespace mlir::edsc::intrinsics;
-using namespace mlir::edsc::ops;
-
-Value mlir::edsc::ops::vector_contraction(
- StructuredIndexed A, StructuredIndexed B, StructuredIndexed C,
- ArrayRef<IteratorType> iteratorTypes) {
- using IndexingExprs = ArrayRef<ArrayRef<AffineExpr>>;
- return vector_contract(
- A.getValue(), B.getValue(), C.getValue(),
- IndexingExprs{A.getExprs(), B.getExprs(), C.getExprs()},
- ArrayRef<StringRef>{
- llvm::to_vector<8>(llvm::map_range(iteratorTypes, toString))});
-}
-
-Value mlir::edsc::ops::vector_contraction_matmul(Value A, Value B, Value C) {
- AffineExpr m, n, k;
- bindDims(ScopedContext::getContext(), m, n, k);
- return vector_contraction(StructuredIndexed(A, {m, k}),
- StructuredIndexed(B, {k, n}),
- StructuredIndexed(C, {m, n}),
- {IteratorType::Parallel, IteratorType::Parallel,
- IteratorType::Reduction});
-}
diff --git a/mlir/lib/Dialect/Vector/VectorTransforms.cpp b/mlir/lib/Dialect/Vector/VectorTransforms.cpp
index f529167a2526..8aa4153e9481 100644
--- a/mlir/lib/Dialect/Vector/VectorTransforms.cpp
+++ b/mlir/lib/Dialect/Vector/VectorTransforms.cpp
@@ -12,17 +12,14 @@
#include <type_traits>
-#include "mlir/Dialect/Affine/EDSC/Builders.h"
-#include "mlir/Dialect/Affine/EDSC/Intrinsics.h"
#include "mlir/Dialect/Affine/IR/AffineOps.h"
-#include "mlir/Dialect/Linalg/EDSC/Intrinsics.h"
-#include "mlir/Dialect/MemRef/EDSC/Intrinsics.h"
+#include "mlir/Dialect/Affine/Utils.h"
+#include "mlir/Dialect/Linalg/IR/LinalgOps.h"
#include "mlir/Dialect/MemRef/IR/MemRef.h"
-#include "mlir/Dialect/SCF/EDSC/Intrinsics.h"
-#include "mlir/Dialect/StandardOps/EDSC/Intrinsics.h"
+#include "mlir/Dialect/SCF/SCF.h"
#include "mlir/Dialect/StandardOps/IR/Ops.h"
#include "mlir/Dialect/Utils/StructuredOpsUtils.h"
-#include "mlir/Dialect/Vector/EDSC/Intrinsics.h"
+
#include "mlir/Dialect/Vector/VectorOps.h"
#include "mlir/Dialect/Vector/VectorTransforms.h"
#include "mlir/Dialect/Vector/VectorUtils.h"
@@ -31,6 +28,7 @@
#include "mlir/IR/Attributes.h"
#include "mlir/IR/Builders.h"
#include "mlir/IR/BuiltinOps.h"
+#include "mlir/IR/ImplicitLocOpBuilder.h"
#include "mlir/IR/Location.h"
#include "mlir/IR/Matchers.h"
#include "mlir/IR/OperationSupport.h"
@@ -2274,18 +2272,18 @@ static Optional<int64_t> extractConstantIndex(Value v) {
// Missing foldings of scf.if make it necessary to perform poor man's folding
// eagerly, especially in the case of unrolling. In the future, this should go
// away once scf.if folds properly.
-static Value createScopedFoldedSLE(Value v, Value ub) {
- using namespace edsc::op;
+static Value createFoldedSLE(OpBuilder &b, Value v, Value ub) {
auto maybeCstV = extractConstantIndex(v);
auto maybeCstUb = extractConstantIndex(ub);
if (maybeCstV && maybeCstUb && *maybeCstV < *maybeCstUb)
return Value();
- return sle(v, ub);
+ return b.create<CmpIOp>(v.getLoc(), CmpIPredicate::sle, v, ub);
}
// Operates under a scoped context to build the condition to ensure that a
// particular VectorTransferOpInterface is in-bounds.
-static Value createScopedInBoundsCond(VectorTransferOpInterface xferOp) {
+static Value createInBoundsCond(OpBuilder &b,
+ VectorTransferOpInterface xferOp) {
assert(xferOp.permutation_map().isMinorIdentity() &&
"Expected minor identity map");
Value inBoundsCond;
@@ -2295,17 +2293,23 @@ static Value createScopedInBoundsCond(VectorTransferOpInterface xferOp) {
// the construction of `inBoundsCond`.
if (xferOp.isDimInBounds(resultIdx))
return;
- int64_t vectorSize = xferOp.getVectorType().getDimSize(resultIdx);
- using namespace edsc::op;
- using namespace edsc::intrinsics;
// Fold or create the check that `index + vector_size` <= `memref_size`.
- Value sum = xferOp.indices()[indicesIdx] + std_constant_index(vectorSize);
- Value cond =
- createScopedFoldedSLE(sum, memref_dim(xferOp.source(), indicesIdx));
+ Location loc = xferOp.getLoc();
+ ImplicitLocOpBuilder lb(loc, b);
+ int64_t vectorSize = xferOp.getVectorType().getDimSize(resultIdx);
+ auto d0 = getAffineDimExpr(0, xferOp.getContext());
+ auto vs = getAffineConstantExpr(vectorSize, xferOp.getContext());
+ Value sum =
+ makeComposedAffineApply(b, loc, d0 + vs, xferOp.indices()[indicesIdx]);
+ Value cond = createFoldedSLE(
+ b, sum, lb.create<memref::DimOp>(xferOp.source(), indicesIdx));
if (!cond)
return;
// Conjunction over all dims for which we are in-bounds.
- inBoundsCond = inBoundsCond ? inBoundsCond && cond : cond;
+ if (inBoundsCond)
+ inBoundsCond = lb.create<AndOp>(inBoundsCond, cond);
+ else
+ inBoundsCond = cond;
});
return inBoundsCond;
}
@@ -2368,9 +2372,10 @@ static MemRefType getCastCompatibleMemRefType(MemRefType aT, MemRefType bT) {
/// Operates under a scoped context to build the intersection between the
/// view `xferOp.source()` @ `xferOp.indices()` and the view `alloc`.
// TODO: view intersection/union/
diff erences should be a proper std op.
-static Value createScopedSubViewIntersection(VectorTransferOpInterface xferOp,
- Value alloc) {
- using namespace edsc::intrinsics;
+static Value createSubViewIntersection(OpBuilder &b,
+ VectorTransferOpInterface xferOp,
+ Value alloc) {
+ ImplicitLocOpBuilder lb(xferOp.getLoc(), b);
int64_t memrefRank = xferOp.getShapedType().getRank();
// TODO: relax this precondition, will require rank-reducing subviews.
assert(memrefRank == alloc.getType().cast<MemRefType>().getRank() &&
@@ -2382,22 +2387,22 @@ static Value createScopedSubViewIntersection(VectorTransferOpInterface xferOp,
auto isaWrite = isa<vector::TransferWriteOp>(xferOp);
xferOp.zipResultAndIndexing([&](int64_t resultIdx, int64_t indicesIdx) {
using MapList = ArrayRef<ArrayRef<AffineExpr>>;
- Value dimMemRef = memref_dim(xferOp.source(), indicesIdx);
- Value dimAlloc = memref_dim(alloc, resultIdx);
+ Value dimMemRef = lb.create<memref::DimOp>(xferOp.source(), indicesIdx);
+ Value dimAlloc = lb.create<memref::DimOp>(alloc, resultIdx);
Value index = xferOp.indices()[indicesIdx];
AffineExpr i, j, k;
bindDims(xferOp.getContext(), i, j, k);
SmallVector<AffineMap, 4> maps =
AffineMap::inferFromExprList(MapList{{i - j, k}});
// affine_min(%dimMemRef - %index, %dimAlloc)
- Value affineMin = affine_min(index.getType(), maps[0],
- ValueRange{dimMemRef, index, dimAlloc});
+ Value affineMin = lb.create<AffineMinOp>(
+ index.getType(), maps[0], ValueRange{dimMemRef, index, dimAlloc});
sizes.push_back(affineMin);
});
SmallVector<OpFoldResult, 4> indices = llvm::to_vector<4>(llvm::map_range(
xferOp.indices(), [](Value idx) -> OpFoldResult { return idx; }));
- return memref_sub_view(
+ return lb.create<memref::SubViewOp>(
isaWrite ? alloc : xferOp.source(), indices, sizes,
SmallVector<OpFoldResult>(memrefRank, OpBuilder(xferOp).getIndexAttr(1)));
}
@@ -2419,40 +2424,38 @@ static Value createScopedSubViewIntersection(VectorTransferOpInterface xferOp,
/// }
/// ```
/// Return the produced scf::IfOp.
-static scf::IfOp createScopedFullPartialLinalgCopy(
- vector::TransferReadOp xferOp, TypeRange returnTypes, Value inBoundsCond,
- MemRefType compatibleMemRefType, Value alloc) {
- using namespace edsc;
- using namespace edsc::intrinsics;
- scf::IfOp fullPartialIfOp;
- Value zero = std_constant_index(0);
+static scf::IfOp
+createFullPartialLinalgCopy(OpBuilder &b, vector::TransferReadOp xferOp,
+ TypeRange returnTypes, Value inBoundsCond,
+ MemRefType compatibleMemRefType, Value alloc) {
+ Location loc = xferOp.getLoc();
+ Value zero = b.create<ConstantIndexOp>(loc, 0);
Value memref = xferOp.source();
- conditionBuilder(
- returnTypes, inBoundsCond,
- [&]() -> scf::ValueVector {
+ return b.create<scf::IfOp>(
+ loc, returnTypes, inBoundsCond,
+ [&](OpBuilder &b, Location loc) {
Value res = memref;
if (compatibleMemRefType != xferOp.getShapedType())
- res = memref_cast(memref, compatibleMemRefType);
+ res = b.create<memref::CastOp>(loc, memref, compatibleMemRefType);
scf::ValueVector viewAndIndices{res};
viewAndIndices.insert(viewAndIndices.end(), xferOp.indices().begin(),
xferOp.indices().end());
- return viewAndIndices;
+ b.create<scf::YieldOp>(loc, viewAndIndices);
},
- [&]() -> scf::ValueVector {
- linalg_fill(alloc, xferOp.padding());
+ [&](OpBuilder &b, Location loc) {
+ b.create<linalg::FillOp>(loc, alloc, xferOp.padding());
// Take partial subview of memref which guarantees no dimension
// overflows.
- Value memRefSubView = createScopedSubViewIntersection(
- cast<VectorTransferOpInterface>(xferOp.getOperation()), alloc);
- linalg_copy(memRefSubView, alloc);
- Value casted = memref_cast(alloc, compatibleMemRefType);
+ Value memRefSubView = createSubViewIntersection(
+ b, cast<VectorTransferOpInterface>(xferOp.getOperation()), alloc);
+ b.create<linalg::CopyOp>(loc, memRefSubView, alloc);
+ Value casted =
+ b.create<memref::CastOp>(loc, alloc, compatibleMemRefType);
scf::ValueVector viewAndIndices{casted};
viewAndIndices.insert(viewAndIndices.end(), xferOp.getTransferRank(),
zero);
- return viewAndIndices;
- },
- &fullPartialIfOp);
- return fullPartialIfOp;
+ b.create<scf::YieldOp>(loc, viewAndIndices);
+ });
}
/// Given an `xferOp` for which:
@@ -2473,41 +2476,39 @@ static scf::IfOp createScopedFullPartialLinalgCopy(
/// }
/// ```
/// Return the produced scf::IfOp.
-static scf::IfOp createScopedFullPartialVectorTransferRead(
- vector::TransferReadOp xferOp, TypeRange returnTypes, Value inBoundsCond,
- MemRefType compatibleMemRefType, Value alloc) {
- using namespace edsc;
- using namespace edsc::intrinsics;
+static scf::IfOp createFullPartialVectorTransferRead(
+ OpBuilder &b, vector::TransferReadOp xferOp, TypeRange returnTypes,
+ Value inBoundsCond, MemRefType compatibleMemRefType, Value alloc) {
+ Location loc = xferOp.getLoc();
scf::IfOp fullPartialIfOp;
- Value zero = std_constant_index(0);
+ Value zero = b.create<ConstantIndexOp>(loc, 0);
Value memref = xferOp.source();
- conditionBuilder(
- returnTypes, inBoundsCond,
- [&]() -> scf::ValueVector {
+ return b.create<scf::IfOp>(
+ loc, returnTypes, inBoundsCond,
+ [&](OpBuilder &b, Location loc) {
Value res = memref;
if (compatibleMemRefType != xferOp.getShapedType())
- res = memref_cast(memref, compatibleMemRefType);
+ res = b.create<memref::CastOp>(loc, memref, compatibleMemRefType);
scf::ValueVector viewAndIndices{res};
viewAndIndices.insert(viewAndIndices.end(), xferOp.indices().begin(),
xferOp.indices().end());
- return viewAndIndices;
+ b.create<scf::YieldOp>(loc, viewAndIndices);
},
- [&]() -> scf::ValueVector {
- Operation *newXfer =
- ScopedContext::getBuilderRef().clone(*xferOp.getOperation());
+ [&](OpBuilder &b, Location loc) {
+ Operation *newXfer = b.clone(*xferOp.getOperation());
Value vector = cast<VectorTransferOpInterface>(newXfer).vector();
- memref_store(vector, vector_type_cast(
- MemRefType::get({}, vector.getType()), alloc));
+ b.create<memref::StoreOp>(
+ loc, vector,
+ b.create<vector::TypeCastOp>(
+ loc, MemRefType::get({}, vector.getType()), alloc));
- Value casted = memref_cast(alloc, compatibleMemRefType);
+ Value casted =
+ b.create<memref::CastOp>(loc, alloc, compatibleMemRefType);
scf::ValueVector viewAndIndices{casted};
viewAndIndices.insert(viewAndIndices.end(), xferOp.getTransferRank(),
zero);
-
- return viewAndIndices;
- },
- &fullPartialIfOp);
- return fullPartialIfOp;
+ b.create<scf::YieldOp>(loc, viewAndIndices);
+ });
}
/// Given an `xferOp` for which:
@@ -2525,33 +2526,35 @@ static scf::IfOp createScopedFullPartialVectorTransferRead(
/// scf.yield %4, ... : compatibleMemRefType, index, index
/// }
/// ```
-static ValueRange getLocationToWriteFullVec(vector::TransferWriteOp xferOp,
- TypeRange returnTypes,
- Value inBoundsCond,
- MemRefType compatibleMemRefType,
- Value alloc) {
- using namespace edsc;
- using namespace edsc::intrinsics;
- Value zero = std_constant_index(0);
+static ValueRange
+getLocationToWriteFullVec(OpBuilder &b, vector::TransferWriteOp xferOp,
+ TypeRange returnTypes, Value inBoundsCond,
+ MemRefType compatibleMemRefType, Value alloc) {
+ Location loc = xferOp.getLoc();
+ Value zero = b.create<ConstantIndexOp>(loc, 0);
Value memref = xferOp.source();
- return conditionBuilder(
- returnTypes, inBoundsCond,
- [&]() -> scf::ValueVector {
- Value res = memref;
- if (compatibleMemRefType != xferOp.getShapedType())
- res = memref_cast(memref, compatibleMemRefType);
- scf::ValueVector viewAndIndices{res};
- viewAndIndices.insert(viewAndIndices.end(), xferOp.indices().begin(),
- xferOp.indices().end());
- return viewAndIndices;
- },
- [&]() -> scf::ValueVector {
- Value casted = memref_cast(alloc, compatibleMemRefType);
- scf::ValueVector viewAndIndices{casted};
- viewAndIndices.insert(viewAndIndices.end(), xferOp.getTransferRank(),
- zero);
- return viewAndIndices;
- });
+ return b
+ .create<scf::IfOp>(
+ loc, returnTypes, inBoundsCond,
+ [&](OpBuilder &b, Location loc) {
+ Value res = memref;
+ if (compatibleMemRefType != xferOp.getShapedType())
+ res = b.create<memref::CastOp>(loc, memref, compatibleMemRefType);
+ scf::ValueVector viewAndIndices{res};
+ viewAndIndices.insert(viewAndIndices.end(),
+ xferOp.indices().begin(),
+ xferOp.indices().end());
+ b.create<scf::YieldOp>(loc, viewAndIndices);
+ },
+ [&](OpBuilder &b, Location loc) {
+ Value casted =
+ b.create<memref::CastOp>(loc, alloc, compatibleMemRefType);
+ scf::ValueVector viewAndIndices{casted};
+ viewAndIndices.insert(viewAndIndices.end(),
+ xferOp.getTransferRank(), zero);
+ b.create<scf::YieldOp>(loc, viewAndIndices);
+ })
+ ->getResults();
}
/// Given an `xferOp` for which:
@@ -2566,19 +2569,17 @@ static ValueRange getLocationToWriteFullVec(vector::TransferWriteOp xferOp,
/// linalg.copy(%3, %view)
/// }
/// ```
-static void createScopedFullPartialLinalgCopy(vector::TransferWriteOp xferOp,
- Value inBoundsCond, Value alloc) {
- using namespace edsc;
- using namespace edsc::intrinsics;
- auto &b = ScopedContext::getBuilderRef();
- auto notInBounds = b.create<XOrOp>(
- xferOp->getLoc(), inBoundsCond,
- b.create<::mlir::ConstantIntOp>(xferOp.getLoc(), true, 1));
-
- conditionBuilder(notInBounds, [&]() {
- Value memRefSubView = createScopedSubViewIntersection(
- cast<VectorTransferOpInterface>(xferOp.getOperation()), alloc);
- linalg_copy(memRefSubView, xferOp.source());
+static void createFullPartialLinalgCopy(OpBuilder &b,
+ vector::TransferWriteOp xferOp,
+ Value inBoundsCond, Value alloc) {
+ ImplicitLocOpBuilder lb(xferOp.getLoc(), b);
+ auto notInBounds =
+ lb.create<XOrOp>(inBoundsCond, lb.create<ConstantIntOp>(true, 1));
+ lb.create<scf::IfOp>(notInBounds, [&](OpBuilder &b, Location loc) {
+ Value memRefSubView = createSubViewIntersection(
+ b, cast<VectorTransferOpInterface>(xferOp.getOperation()), alloc);
+ b.create<linalg::CopyOp>(loc, memRefSubView, xferOp.source());
+ b.create<scf::YieldOp>(loc, ValueRange{});
});
}
@@ -2594,23 +2595,21 @@ static void createScopedFullPartialLinalgCopy(vector::TransferWriteOp xferOp,
/// vector.transfer_write %2, %view[...] : memref<A...>, vector<...>
/// }
/// ```
-static void
-createScopedFullPartialVectorTransferWrite(vector::TransferWriteOp xferOp,
- Value inBoundsCond, Value alloc) {
- using namespace edsc;
- using namespace edsc::intrinsics;
- auto &b = ScopedContext::getBuilderRef();
- auto notInBounds = b.create<XOrOp>(
- xferOp->getLoc(), inBoundsCond,
- b.create<::mlir::ConstantIntOp>(xferOp.getLoc(), true, 1));
- conditionBuilder(notInBounds, [&]() {
+static void createFullPartialVectorTransferWrite(OpBuilder &b,
+ vector::TransferWriteOp xferOp,
+ Value inBoundsCond,
+ Value alloc) {
+ ImplicitLocOpBuilder lb(xferOp.getLoc(), b);
+ auto notInBounds =
+ lb.create<XOrOp>(inBoundsCond, lb.create<ConstantIntOp>(true, 1));
+ lb.create<scf::IfOp>(notInBounds, [&](OpBuilder &b, Location loc) {
BlockAndValueMapping mapping;
-
- Value load = memref_load(vector_type_cast(
- MemRefType::get({}, xferOp.vector().getType()), alloc));
-
+ Value load = b.create<memref::LoadOp>(
+ loc, b.create<vector::TypeCastOp>(
+ loc, MemRefType::get({}, xferOp.vector().getType()), alloc));
mapping.map(xferOp.vector(), load);
b.clone(*xferOp.getOperation(), mapping);
+ b.create<scf::YieldOp>(loc, ValueRange{});
});
}
@@ -2677,9 +2676,6 @@ createScopedFullPartialVectorTransferWrite(vector::TransferWriteOp xferOp,
LogicalResult mlir::vector::splitFullAndPartialTransfer(
OpBuilder &b, VectorTransferOpInterface xferOp,
VectorTransformsOptions options, scf::IfOp *ifOp) {
- using namespace edsc;
- using namespace edsc::intrinsics;
-
if (options.vectorTransferSplit == VectorTransferSplit::None)
return failure();
@@ -2709,9 +2705,8 @@ LogicalResult mlir::vector::splitFullAndPartialTransfer(
OpBuilder::InsertionGuard guard(b);
b.setInsertionPoint(xferOp);
- ScopedContext scope(b, xferOp.getLoc());
- Value inBoundsCond = createScopedInBoundsCond(
- cast<VectorTransferOpInterface>(xferOp.getOperation()));
+ Value inBoundsCond = createInBoundsCond(
+ b, cast<VectorTransferOpInterface>(xferOp.getOperation()));
if (!inBoundsCond)
return failure();
@@ -2723,8 +2718,9 @@ LogicalResult mlir::vector::splitFullAndPartialTransfer(
b.setInsertionPointToStart(&funcOp.getRegion().front());
auto shape = xferOp.getVectorType().getShape();
Type elementType = xferOp.getVectorType().getElementType();
- alloc = memref_alloca(MemRefType::get(shape, elementType), ValueRange{},
- b.getI64IntegerAttr(32));
+ alloc = b.create<memref::AllocaOp>(funcOp.getLoc(),
+ MemRefType::get(shape, elementType),
+ ValueRange{}, b.getI64IntegerAttr(32));
}
MemRefType compatibleMemRefType =
@@ -2739,12 +2735,12 @@ LogicalResult mlir::vector::splitFullAndPartialTransfer(
// Read case: full fill + partial copy -> in-bounds vector.xfer_read.
scf::IfOp fullPartialIfOp =
options.vectorTransferSplit == VectorTransferSplit::VectorTransfer
- ? createScopedFullPartialVectorTransferRead(
- xferReadOp, returnTypes, inBoundsCond, compatibleMemRefType,
- alloc)
- : createScopedFullPartialLinalgCopy(xferReadOp, returnTypes,
- inBoundsCond,
- compatibleMemRefType, alloc);
+ ? createFullPartialVectorTransferRead(b, xferReadOp, returnTypes,
+ inBoundsCond,
+ compatibleMemRefType, alloc)
+ : createFullPartialLinalgCopy(b, xferReadOp, returnTypes,
+ inBoundsCond, compatibleMemRefType,
+ alloc);
if (ifOp)
*ifOp = fullPartialIfOp;
@@ -2761,7 +2757,7 @@ LogicalResult mlir::vector::splitFullAndPartialTransfer(
// Decide which location to write the entire vector to.
auto memrefAndIndices = getLocationToWriteFullVec(
- xferWriteOp, returnTypes, inBoundsCond, compatibleMemRefType, alloc);
+ b, xferWriteOp, returnTypes, inBoundsCond, compatibleMemRefType, alloc);
// Do an in bounds write to either the output or the extra allocated buffer.
// The operation is cloned to prevent deleting information needed for the
@@ -2775,10 +2771,9 @@ LogicalResult mlir::vector::splitFullAndPartialTransfer(
// Create a potential copy from the allocated buffer to the final output in
// the slow path case.
if (options.vectorTransferSplit == VectorTransferSplit::VectorTransfer)
- createScopedFullPartialVectorTransferWrite(xferWriteOp, inBoundsCond,
- alloc);
+ createFullPartialVectorTransferWrite(b, xferWriteOp, inBoundsCond, alloc);
else
- createScopedFullPartialLinalgCopy(xferWriteOp, inBoundsCond, alloc);
+ createFullPartialLinalgCopy(b, xferWriteOp, inBoundsCond, alloc);
xferOp->erase();
@@ -2864,27 +2859,27 @@ struct TransferReadExtractPattern
return failure();
if (read.mask())
return failure();
- edsc::ScopedContext scope(rewriter, read.getLoc());
- using mlir::edsc::op::operator+;
- using mlir::edsc::op::operator*;
- using namespace mlir::edsc::intrinsics;
+
SmallVector<Value, 4> indices(read.indices().begin(), read.indices().end());
AffineMap map = extract.map();
unsigned idCount = 0;
+ ImplicitLocOpBuilder lb(read.getLoc(), rewriter);
for (auto expr : map.getResults()) {
+ AffineExpr d0, d1;
+ bindDims(read.getContext(), d0, d1);
unsigned pos = expr.cast<AffineDimExpr>().getPosition();
+ auto scale = getAffineConstantExpr(
+ extract.getResultType().getDimSize(pos), read.getContext());
indices[pos] =
- indices[pos] +
- extract.ids()[idCount++] *
- std_constant_index(extract.getResultType().getDimSize(pos));
+ makeComposedAffineApply(rewriter, read.getLoc(), d0 + scale * d1,
+ {indices[pos], extract.ids()[idCount++]});
}
- Value newRead = vector_transfer_read(extract.getType(), read.source(),
- indices, read.permutation_map(),
- read.padding(), read.in_boundsAttr());
- Value dest = rewriter.create<ConstantOp>(
- read.getLoc(), read.getType(), rewriter.getZeroAttr(read.getType()));
- newRead = rewriter.create<vector::InsertMapOp>(read.getLoc(), newRead, dest,
- extract.ids());
+ Value newRead = lb.create<vector::TransferReadOp>(
+ extract.getType(), read.source(), indices, read.permutation_map(),
+ read.padding(), read.in_boundsAttr());
+ Value dest = lb.create<ConstantOp>(read.getType(),
+ rewriter.getZeroAttr(read.getType()));
+ newRead = lb.create<vector::InsertMapOp>(newRead, dest, extract.ids());
rewriter.replaceOp(read, newRead);
return success();
}
@@ -2901,23 +2896,24 @@ struct TransferWriteInsertPattern
return failure();
if (write.mask())
return failure();
- edsc::ScopedContext scope(rewriter, write.getLoc());
- using mlir::edsc::op::operator+;
- using mlir::edsc::op::operator*;
- using namespace mlir::edsc::intrinsics;
SmallVector<Value, 4> indices(write.indices().begin(),
write.indices().end());
AffineMap map = insert.map();
unsigned idCount = 0;
+ Location loc = write.getLoc();
for (auto expr : map.getResults()) {
+ AffineExpr d0, d1;
+ bindDims(write.getContext(), d0, d1);
unsigned pos = expr.cast<AffineDimExpr>().getPosition();
+ auto scale = getAffineConstantExpr(
+ insert.getSourceVectorType().getDimSize(pos), write.getContext());
indices[pos] =
- indices[pos] +
- insert.ids()[idCount++] *
- std_constant_index(insert.getSourceVectorType().getDimSize(pos));
+ makeComposedAffineApply(rewriter, loc, d0 + scale * d1,
+ {indices[pos], insert.ids()[idCount++]});
}
- vector_transfer_write(insert.vector(), write.source(), indices,
- write.permutation_map(), write.in_boundsAttr());
+ rewriter.create<vector::TransferWriteOp>(
+ loc, insert.vector(), write.source(), indices, write.permutation_map(),
+ write.in_boundsAttr());
rewriter.eraseOp(write);
return success();
}
@@ -3175,23 +3171,23 @@ struct TransferWritePermutationLowering
SmallVector<int64_t> indices;
llvm::transform(comp.getResults(), std::back_inserter(indices),
[](AffineExpr expr) {
- return expr.dyn_cast<AffineDimExpr>().getPosition();
- });
+ return expr.dyn_cast<AffineDimExpr>().getPosition();
+ });
// Transpose mask operand.
- Value newMask = op.mask()
- ? rewriter.create<vector::TransposeOp>(op.getLoc(), op.mask(), indices)
- : Value();
+ Value newMask = op.mask() ? rewriter.create<vector::TransposeOp>(
+ op.getLoc(), op.mask(), indices)
+ : Value();
// Transpose in_bounds attribute.
- ArrayAttr newInBounds = op.in_bounds()
- ? transposeInBoundsAttr(rewriter, op.in_bounds().getValue(),
- permutation)
- : ArrayAttr();
+ ArrayAttr newInBounds =
+ op.in_bounds() ? transposeInBoundsAttr(
+ rewriter, op.in_bounds().getValue(), permutation)
+ : ArrayAttr();
// Generate new transfer_write operation.
- Value newVec = rewriter.create<vector::TransposeOp>(
- op.getLoc(), op.vector(), indices);
+ Value newVec =
+ rewriter.create<vector::TransposeOp>(op.getLoc(), op.vector(), indices);
auto newMap = AffineMap::getMinorIdentityMap(
map.getNumDims(), map.getNumResults(), rewriter.getContext());
rewriter.replaceOpWithNewOp<vector::TransferWriteOp>(
diff --git a/mlir/test/CMakeLists.txt b/mlir/test/CMakeLists.txt
index f8e349b5b606..614a990bace0 100644
--- a/mlir/test/CMakeLists.txt
+++ b/mlir/test/CMakeLists.txt
@@ -1,5 +1,4 @@
add_subdirectory(CAPI)
-add_subdirectory(EDSC)
add_subdirectory(SDBM)
add_subdirectory(lib)
@@ -63,7 +62,6 @@ set(MLIR_TEST_DEPENDS
mlir-capi-pass-test
mlir-capi-sparse-tensor-test
mlir-cpu-runner
- mlir-edsc-builder-api-test
mlir-linalg-ods-gen
mlir-lsp-server
mlir-opt
diff --git a/mlir/test/EDSC/CMakeLists.txt b/mlir/test/EDSC/CMakeLists.txt
deleted file mode 100644
index d4380561854b..000000000000
--- a/mlir/test/EDSC/CMakeLists.txt
+++ /dev/null
@@ -1,26 +0,0 @@
-set(LLVM_LINK_COMPONENTS
- Core
- Support
- )
-add_llvm_executable(mlir-edsc-builder-api-test
- builder-api-test.cpp
-)
-
-llvm_update_compile_flags(mlir-edsc-builder-api-test)
-
-target_link_libraries(mlir-edsc-builder-api-test
- PRIVATE
- MLIRAffine
- MLIRAffineEDSC
- MLIREDSC
- MLIRIR
- MLIRLinalg
- MLIRLinalgEDSC
- MLIRMemRef
- MLIRSCF
- MLIRStandard
- MLIRTransforms
- MLIRVector
- )
-
-target_include_directories(mlir-edsc-builder-api-test PRIVATE ..)
diff --git a/mlir/test/EDSC/builder-api-test.cpp b/mlir/test/EDSC/builder-api-test.cpp
deleted file mode 100644
index ed7fef160ff9..000000000000
--- a/mlir/test/EDSC/builder-api-test.cpp
+++ /dev/null
@@ -1,1254 +0,0 @@
-//===- builder-api-test.cpp - Tests for Declarative Builder APIs ----------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-// RUN: mlir-edsc-builder-api-test | FileCheck %s
-
-#include "mlir/Dialect/Affine/EDSC/Intrinsics.h"
-#include "mlir/Dialect/Linalg/EDSC/Builders.h"
-#include "mlir/Dialect/Linalg/EDSC/Intrinsics.h"
-#include "mlir/Dialect/Math/IR/Math.h"
-#include "mlir/Dialect/MemRef/EDSC/Intrinsics.h"
-#include "mlir/Dialect/SCF/EDSC/Intrinsics.h"
-#include "mlir/Dialect/StandardOps/EDSC/Intrinsics.h"
-#include "mlir/Dialect/Vector/EDSC/Intrinsics.h"
-#include "mlir/EDSC/Builders.h"
-#include "mlir/IR/AffineExpr.h"
-#include "mlir/IR/Builders.h"
-#include "mlir/IR/BuiltinOps.h"
-#include "mlir/IR/BuiltinTypes.h"
-#include "mlir/IR/IntegerSet.h"
-#include "mlir/IR/MLIRContext.h"
-#include "mlir/IR/Types.h"
-#include "mlir/Pass/Pass.h"
-#include "mlir/Pass/PassManager.h"
-#include "mlir/Transforms/LoopUtils.h"
-#include "mlir/Transforms/Passes.h"
-
-#include "APITest.h"
-
-#include "llvm/Support/raw_ostream.h"
-
-using namespace mlir;
-using namespace mlir::edsc;
-using namespace mlir::edsc::intrinsics;
-
-static MLIRContext &globalContext() {
- static thread_local MLIRContext context;
- static thread_local bool initOnce = [&]() {
- // clang-format off
- context.loadDialect<AffineDialect,
- scf::SCFDialect,
- linalg::LinalgDialect,
- math::MathDialect,
- memref::MemRefDialect,
- StandardOpsDialect,
- vector::VectorDialect>();
- // clang-format on
- return true;
- }();
- (void)initOnce;
- context.allowUnregisteredDialects();
- return context;
-}
-
-static FuncOp makeFunction(StringRef name, ArrayRef<Type> results = {},
- ArrayRef<Type> args = {}) {
- auto &ctx = globalContext();
- auto function = FuncOp::create(UnknownLoc::get(&ctx), name,
- FunctionType::get(&ctx, args, results));
- function.addEntryBlock();
- return function;
-}
-
-TEST_FUNC(builder_dynamic_for_func_args) {
- auto indexType = IndexType::get(&globalContext());
- auto f32Type = FloatType::getF32(&globalContext());
- auto f =
- makeFunction("builder_dynamic_for_func_args", {}, {indexType, indexType});
-
- OpBuilder builder(f.getBody());
- ScopedContext scope(builder, f.getLoc());
- Value lb(f.getArgument(0)), ub(f.getArgument(1));
- Value f7(std_constant_float(llvm::APFloat(7.0f), f32Type));
- Value f13(std_constant_float(llvm::APFloat(13.0f), f32Type));
- Value i7(std_constant_int(7, 32));
- Value i13(std_constant_int(13, 32));
- affineLoopBuilder(lb, ub, 3, [&](Value i) {
- using namespace edsc::op;
- lb *std_constant_index(3) + ub;
- lb + std_constant_index(3);
- affineLoopBuilder(lb, ub, 2, [&](Value j) {
- ceilDiv(std_constant_index(31) * floorDiv(i + j * std_constant_index(3),
- std_constant_index(32)),
- std_constant_index(32));
- ((f7 + f13) / f7) % f13 - f7 *f13;
- ((i7 + i13) / i7) % i13 - i7 *i13;
- });
- });
-
- // clang-format off
- // CHECK-LABEL: func @builder_dynamic_for_func_args(%{{.*}}: index, %{{.*}}: index) {
- // CHECK: affine.for %{{.*}} = affine_map<(d0) -> (d0)>(%{{.*}}) to affine_map<(d0) -> (d0)>(%{{.*}}) step 3 {
- // CHECK: {{.*}} = affine.apply affine_map<()[s0] -> (s0 * 3)>()[%{{.*}}]
- // CHECK: {{.*}} = affine.apply affine_map<()[s0, s1] -> (s0 * 3 + s1)>()[%{{.*}}, %{{.*}}]
- // CHECK: {{.*}} = affine.apply affine_map<()[s0] -> (s0 + 3)>()[%{{.*}}]
- // CHECK: affine.for %{{.*}} = affine_map<(d0) -> (d0)>(%{{.*}}) to affine_map<(d0) -> (d0)>(%{{.*}}) step 2 {
- // CHECK: {{.*}} = affine.apply affine_map<(d0, d1) -> ((d0 + d1 * 3) floordiv 32)>(%{{.*}}, %{{.*}})
- // CHECK: {{.*}} = affine.apply affine_map<(d0, d1) -> (((d0 + d1 * 3) floordiv 32) * 31)>(%{{.*}}, %{{.*}})
- // CHECK: {{.*}} = affine.apply affine_map<(d0, d1) -> ((((d0 + d1 * 3) floordiv 32) * 31) ceildiv 32)>(%{{.*}}, %{{.*}})
- // CHECK-DAG: [[rf1:%[0-9]+]] = addf {{.*}}, {{.*}} : f32
- // CHECK-DAG: [[rf2:%[0-9]+]] = divf [[rf1]], {{.*}} : f32
- // CHECK-DAG: [[rf3:%[0-9]+]] = remf [[rf2]], {{.*}} : f32
- // CHECK-DAG: [[rf4:%[0-9]+]] = mulf {{.*}}, {{.*}} : f32
- // CHECK: {{.*}} = subf [[rf3]], [[rf4]] : f32
- // CHECK-DAG: [[ri1:%[0-9]+]] = addi {{.*}}, {{.*}} : i32
- // CHECK-DAG: [[ri2:%[0-9]+]] = divi_signed [[ri1]], {{.*}} : i32
- // CHECK-DAG: [[ri3:%[0-9]+]] = remi_signed [[ri2]], {{.*}} : i32
- // CHECK-DAG: [[ri4:%[0-9]+]] = muli {{.*}}, {{.*}} : i32
- // CHECK: {{.*}} = subi [[ri3]], [[ri4]] : i32
- // clang-format on
- f.print(llvm::outs(), OpPrintingFlags().useLocalScope());
- f.erase();
-}
-
-TEST_FUNC(builder_dynamic_for) {
- auto indexType = IndexType::get(&globalContext());
- auto f = makeFunction("builder_dynamic_for", {},
- {indexType, indexType, indexType, indexType});
-
- OpBuilder builder(f.getBody());
- ScopedContext scope(builder, f.getLoc());
- Value i, a(f.getArgument(0)), b(f.getArgument(1)), c(f.getArgument(2)),
- d(f.getArgument(3));
- using namespace edsc::op;
- affineLoopBuilder(a - b, c + d, 2);
-
- // clang-format off
- // CHECK-LABEL: func @builder_dynamic_for(%{{.*}}: index, %{{.*}}: index, %{{.*}}: index, %{{.*}}: index) {
- // CHECK-DAG: [[r0:%[0-9]+]] = affine.apply affine_map<()[s0, s1] -> (s0 - s1)>()[%{{.*}}, %{{.*}}]
- // CHECK-DAG: [[r1:%[0-9]+]] = affine.apply affine_map<()[s0, s1] -> (s0 + s1)>()[%{{.*}}, %{{.*}}]
- // CHECK-NEXT: affine.for %{{.*}} = affine_map<(d0) -> (d0)>([[r0]]) to affine_map<(d0) -> (d0)>([[r1]]) step 2 {
- // clang-format on
- f.print(llvm::outs(), OpPrintingFlags().useLocalScope());
- f.erase();
-}
-
-TEST_FUNC(builder_loop_for) {
- auto indexType = IndexType::get(&globalContext());
- auto f = makeFunction("builder_loop_for", {},
- {indexType, indexType, indexType, indexType});
-
- OpBuilder builder(f.getBody());
- ScopedContext scope(builder, f.getLoc());
- Value a(f.getArgument(0)), b(f.getArgument(1)), c(f.getArgument(2)),
- d(f.getArgument(3));
- using namespace edsc::op;
- loopNestBuilder(a - b, c + d, a);
-
- // clang-format off
- // CHECK-LABEL: func @builder_loop_for(%{{.*}}: index, %{{.*}}: index, %{{.*}}: index, %{{.*}}: index) {
- // CHECK-DAG: [[r0:%[0-9]+]] = affine.apply affine_map<()[s0, s1] -> (s0 - s1)>()[%{{.*}}, %{{.*}}]
- // CHECK-DAG: [[r1:%[0-9]+]] = affine.apply affine_map<()[s0, s1] -> (s0 + s1)>()[%{{.*}}, %{{.*}}]
- // CHECK-NEXT: scf.for %{{.*}} = [[r0]] to [[r1]] step {{.*}} {
- // clang-format on
- f.print(llvm::outs(), OpPrintingFlags().useLocalScope());
- f.erase();
-}
-
-TEST_FUNC(builder_max_min_for) {
- auto indexType = IndexType::get(&globalContext());
- auto f = makeFunction("builder_max_min_for", {},
- {indexType, indexType, indexType, indexType});
-
- OpBuilder builder(f.getBody());
- ScopedContext scope(builder, f.getLoc());
- Value lb1(f.getArgument(0)), lb2(f.getArgument(1)), ub1(f.getArgument(2)),
- ub2(f.getArgument(3));
- affineLoopBuilder({lb1, lb2}, {ub1, ub2}, 1);
- std_ret();
-
- // clang-format off
- // CHECK-LABEL: func @builder_max_min_for(%{{.*}}: index, %{{.*}}: index, %{{.*}}: index, %{{.*}}: index) {
- // CHECK: affine.for %{{.*}} = max affine_map<(d0, d1) -> (d0, d1)>(%{{.*}}, %{{.*}}) to min affine_map<(d0, d1) -> (d0, d1)>(%{{.*}}, %{{.*}}) {
- // CHECK: return
- // clang-format on
- f.print(llvm::outs(), OpPrintingFlags().useLocalScope());
- f.erase();
-}
-
-TEST_FUNC(builder_affine_for_iter_args) {
- auto indexType = IndexType::get(&globalContext());
- auto f = makeFunction("builder_affine_for_iter_args", {},
- {indexType, indexType, indexType});
-
- OpBuilder builder(f.getBody());
- ScopedContext scope(builder, f.getLoc());
- Value i, lb_1(f.getArgument(0)), ub_1(f.getArgument(1)),
- ub_2(f.getArgument(2));
- Value c32(std_constant_int(32, 32));
- Value c42(std_constant_int(42, 32));
- using namespace edsc::op;
- affineLoopBuilder(
- lb_1, {ub_1, ub_2}, 2, {c32, c42}, [&](Value iv, ValueRange args) {
- Value sum(args[0] + args[1]);
- builder.create<AffineYieldOp>(f.getLoc(), ValueRange({args[1], sum}));
- });
-
- // clang-format off
- // CHECK-LABEL: func @builder_affine_for_iter_args
- // CHECK: (%[[lb_1:.*]]: index, %[[ub_1:.*]]: index, %[[ub_2:.*]]: index) {
- // CHECK-NEXT: %[[c32:.*]] = constant 32 : i32
- // CHECK-NEXT: %[[c42:.*]] = constant 42 : i32
- // CHECK-NEXT: %{{.*}} = affine.for %{{.*}} = affine_map<(d0) -> (d0)>(%{{.*}}) to min affine_map<(d0, d1) -> (d0, d1)>(%[[ub_1]], %[[ub_2]]) step 2 iter_args(%[[iarg_1:.*]] = %[[c32]], %[[iarg_2:.*]] = %[[c42]]) -> (i32, i32) {
- // CHECK-NEXT: %[[sum:.*]] = addi %[[iarg_1]], %[[iarg_2]] : i32
- // CHECK-NEXT: affine.yield %[[iarg_2]], %[[sum]] : i32, i32
- // CHECK-NEXT: }
- // clang-format on
- f.print(llvm::outs(), OpPrintingFlags().useLocalScope());
- f.erase();
-}
-
-TEST_FUNC(builder_block_append) {
- using namespace edsc::op;
- auto f = makeFunction("builder_blocks");
-
- OpBuilder builder(f.getBody());
- ScopedContext scope(builder, f.getLoc());
-
- Block *b =
- buildInNewBlock(TypeRange(), [&](ValueRange) { std_constant_index(0); });
- appendToBlock(b, [&](ValueRange) { std_constant_index(1); });
- appendToBlock(b, [&](ValueRange) { std_ret(); });
- // Get back to entry block and add a branch into "b".
- appendToBlock(&f.front(), [&](ValueRange) { std_br(b, {}); });
-
- // clang-format off
- // CHECK-LABEL: @builder_blocks
- // CHECK-NEXT: br ^bb1
- // CHECK-NEXT: ^bb1: // pred: ^bb0
- // CHECK-NEXT: constant 0 : index
- // CHECK-NEXT: constant 1 : index
- // CHECK-NEXT: return
- // CHECK-NEXT: }
- // clang-format on
- f.print(llvm::outs(), OpPrintingFlags().useLocalScope());
- f.erase();
-}
-
-TEST_FUNC(builder_blocks) {
- using namespace edsc::op;
- auto f = makeFunction("builder_blocks");
-
- OpBuilder builder(f.getBody());
- ScopedContext scope(builder, f.getLoc());
- Value c1(std_constant_int(42, 32)), c2(std_constant_int(1234, 32));
- ReturnOp ret = std_ret();
-
- Block *b1 = createBlock({c1.getType(), c1.getType()});
- Block *b2 = buildInNewBlock({c1.getType(), c1.getType()},
- [&](ValueRange args) { std_br(b1, args); });
- // The insertion point within the toplevel function is now past b2, we will
- // need to get back the entry block.
- // This is what happens with unstructured control-flow.
- appendToBlock(b1, [&](ValueRange args) {
- Value r = args[0] + args[1];
- std_br(b2, {args[0], r});
- });
- // Get back to entry block and add a branch into b1.
- appendToBlock(&f.front(), [&](ValueRange) { std_br(b1, {c1, c2}); });
- ret.erase();
-
- // clang-format off
- // CHECK-LABEL: @builder_blocks
- // CHECK: %{{.*}} = constant 42 : i32
- // CHECK-NEXT: %{{.*}} = constant 1234 : i32
- // CHECK-NEXT: br ^bb1(%{{.*}}, %{{.*}} : i32, i32)
- // CHECK-NEXT: ^bb1(%{{.*}}: i32, %{{.*}}: i32): // 2 preds: ^bb0, ^bb2
- // CHECK-NEXT: %{{.*}} = addi %{{.*}}, %{{.*}} : i32
- // CHECK-NEXT: br ^bb2(%{{.*}}, %{{.*}} : i32, i32)
- // CHECK-NEXT: ^bb2(%{{.*}}: i32, %{{.*}}: i32): // pred: ^bb1
- // CHECK-NEXT: br ^bb1(%{{.*}}, %{{.*}} : i32, i32)
- // CHECK-NEXT: }
- // clang-format on
- f.print(llvm::outs(), OpPrintingFlags().useLocalScope());
- f.erase();
-}
-
-TEST_FUNC(builder_cond_branch) {
- auto f = makeFunction("builder_cond_branch", {},
- {IntegerType::get(&globalContext(), 1)});
-
- OpBuilder builder(f.getBody());
- ScopedContext scope(builder, f.getLoc());
- Value c32(std_constant_int(32, 32)), c64(std_constant_int(64, 64)),
- c42(std_constant_int(42, 32));
- ReturnOp ret = std_ret();
-
- Block *b1 = buildInNewBlock(c32.getType(), [&](ValueRange) { std_ret(); });
- Block *b2 = buildInNewBlock({c64.getType(), c32.getType()},
- [&](ValueRange) { std_ret(); });
- // Get back to entry block and add a conditional branch.
- appendToBlock(&f.front(), [&](ValueRange args) {
- std_cond_br(args[0], b1, {c32}, b2, {c64, c42});
- });
- ret.erase();
-
- // clang-format off
- // CHECK-LABEL: @builder_cond_branch
- // CHECK: %{{.*}} = constant 32 : i32
- // CHECK-NEXT: %{{.*}} = constant 64 : i64
- // CHECK-NEXT: %{{.*}} = constant 42 : i32
- // CHECK-NEXT: cond_br %{{.*}}, ^bb1(%{{.*}} : i32), ^bb2(%{{.*}}, %{{.*}} : i64, i32)
- // CHECK-NEXT: ^bb1(%{{.*}}: i32): // pred: ^bb0
- // CHECK-NEXT: return
- // CHECK-NEXT: ^bb2(%{{.*}}: i64, %{{.*}}: i32): // pred: ^bb0
- // CHECK-NEXT: return
- // clang-format on
- f.print(llvm::outs(), OpPrintingFlags().useLocalScope());
- f.erase();
-}
-
-TEST_FUNC(builder_helpers) {
- using namespace edsc::op;
- auto f32Type = FloatType::getF32(&globalContext());
- auto memrefType =
- MemRefType::get({ShapedType::kDynamicSize, ShapedType::kDynamicSize,
- ShapedType::kDynamicSize},
- f32Type, {}, 0);
- auto f =
- makeFunction("builder_helpers", {}, {memrefType, memrefType, memrefType});
-
- OpBuilder builder(f.getBody());
- ScopedContext scope(builder, f.getLoc());
- // clang-format off
- Value f7 = std_constant_float(llvm::APFloat(7.0f), f32Type);
- MemRefBoundsCapture vA(f.getArgument(0)), vB(f.getArgument(1)),
- vC(f.getArgument(2));
- AffineIndexedValue A(f.getArgument(0)), B(f.getArgument(1)), C(f.getArgument(2));
- Value lb0, lb1, lb2, ub0, ub1, ub2;
- int64_t step0, step1, step2;
- std::tie(lb0, ub0, step0) = vA.range(0);
- std::tie(lb1, ub1, step1) = vA.range(1);
- lb2 = vA.lb(2);
- ub2 = vA.ub(2);
- step2 = vA.step(2);
- affineLoopNestBuilder({lb0, lb1}, {ub0, ub1}, {step0, step1}, [&](ValueRange ivs) {
- Value i = ivs[0];
- Value j = ivs[1];
- affineLoopBuilder(lb2, ub2, step2, [&](Value k1){
- C(i, j, k1) = f7 + A(i, j, k1) + B(i, j, k1);
- });
- affineLoopBuilder(lb2, ub2, step2, [&](Value k2){
- C(i, j, k2) += A(i, j, k2) + B(i, j, k2);
- });
- });
-
- // clang-format off
- // CHECK-LABEL: @builder_helpers
- // CHECK: affine.for %{{.*}} = affine_map<(d0) -> (d0)>({{.*}}) to affine_map<(d0) -> (d0)>({{.*}}) {
- // CHECK-NEXT: affine.for %{{.*}} = affine_map<(d0) -> (d0)>({{.*}}) to affine_map<(d0) -> (d0)>({{.*}}) {
- // CHECK-NEXT: affine.for %{{.*}} = affine_map<(d0) -> (d0)>({{.*}}) to affine_map<(d0) -> (d0)>({{.*}}) {
- // CHECK-DAG: [[a:%.*]] = affine.load %arg0[%{{.*}}, %{{.*}}, %{{.*}}] : memref<?x?x?xf32>
- // CHECK-DAG: [[b:%.*]] = addf {{.*}}, [[a]] : f32
- // CHECK-DAG: [[c:%.*]] = affine.load %arg1[%{{.*}}, %{{.*}}, %{{.*}}] : memref<?x?x?xf32>
- // CHECK-DAG: [[d:%.*]] = addf [[b]], [[c]] : f32
- // CHECK-NEXT: affine.store [[d]], %{{.*}}[%{{.*}}, %{{.*}}, %{{.*}}] : memref<?x?x?xf32>
- // CHECK-NEXT: }
- // CHECK-NEXT: affine.for %{{.*}} = affine_map<(d0) -> (d0)>(%{{.*}}) to affine_map<(d0) -> (d0)>(%{{.*}}) {
- // CHECK-DAG: [[a:%.*]] = affine.load %{{.*}}[%{{.*}}, %{{.*}}, %{{.*}}] : memref<?x?x?xf32>
- // CHECK-DAG: [[b:%.*]] = affine.load %{{.*}}[%{{.*}}, %{{.*}}, %{{.*}}] : memref<?x?x?xf32>
- // CHECK-DAG: [[c:%.*]] = addf [[b]], [[a]] : f32
- // CHECK-DAG: [[d:%.*]] = affine.load %{{.*}}[%{{.*}}, %{{.*}}, %{{.*}}] : memref<?x?x?xf32>
- // CHECK-DAG: [[e:%.*]] = addf [[d]], [[c]] : f32
- // CHECK-NEXT: affine.store [[e]], %{{.*}}[%{{.*}}, %{{.*}}, %{{.*}}] : memref<?x?x?xf32>
- // clang-format on
- f.print(llvm::outs(), OpPrintingFlags().useLocalScope());
- f.erase();
-}
-
-TEST_FUNC(insertion_in_block) {
- using namespace edsc::op;
- auto indexType = IndexType::get(&globalContext());
- auto f = makeFunction("insertion_in_block", {}, {indexType, indexType});
-
- OpBuilder builder(f.getBody());
- ScopedContext scope(builder, f.getLoc());
- std_constant_int(0, 32);
- buildInNewBlock({}, [&](ValueRange) { std_constant_int(1, 32); });
- std_constant_int(2, 32);
- // clang-format off
- // CHECK-LABEL: @insertion_in_block
- // CHECK: {{.*}} = constant 0 : i32
- // CHECK: {{.*}} = constant 2 : i32
- // CHECK: ^bb1: // no predecessors
- // CHECK: {{.*}} = constant 1 : i32
- // clang-format on
- f.print(llvm::outs(), OpPrintingFlags().useLocalScope());
- f.erase();
-}
-
-TEST_FUNC(zero_and_std_sign_extendi_op_i1_to_i8) {
- using namespace edsc::op;
- auto i1Type = IntegerType::get(&globalContext(), 1);
- auto i8Type = IntegerType::get(&globalContext(), 8);
- auto memrefType = MemRefType::get({}, i1Type, {}, 0);
- auto f = makeFunction("zero_and_std_sign_extendi_op", {},
- {memrefType, memrefType});
-
- OpBuilder builder(f.getBody());
- ScopedContext scope(builder, f.getLoc());
- AffineIndexedValue A(f.getArgument(0));
- AffineIndexedValue B(f.getArgument(1));
- // clang-format off
- edsc::intrinsics::std_zero_extendi(A, i8Type);
- edsc::intrinsics::std_sign_extendi(B, i8Type);
- // CHECK-LABEL: @zero_and_std_sign_extendi_op
- // CHECK: %[[SRC1:.*]] = affine.load
- // CHECK: zexti %[[SRC1]] : i1 to i8
- // CHECK: %[[SRC2:.*]] = affine.load
- // CHECK: sexti %[[SRC2]] : i1 to i8
- // clang-format on
- f.print(llvm::outs(), OpPrintingFlags().useLocalScope());
- f.erase();
-}
-
-TEST_FUNC(operator_or) {
- auto i1Type = IntegerType::get(&globalContext(), /*width=*/1);
- auto f = makeFunction("operator_or", {}, {i1Type, i1Type});
-
- OpBuilder builder(f.getBody());
- ScopedContext scope(builder, f.getLoc());
-
- using op::operator||;
- Value lhs(f.getArgument(0));
- Value rhs(f.getArgument(1));
- lhs || rhs;
-
- // clang-format off
- // CHECK-LABEL: @operator_or
- // CHECK: [[ARG0:%.*]]: i1, [[ARG1:%.*]]: i1
- // CHECK: or [[ARG0]], [[ARG1]]
- // clang-format on
- f.print(llvm::outs(), OpPrintingFlags().useLocalScope());
- f.erase();
-}
-
-TEST_FUNC(operator_and) {
- auto i1Type = IntegerType::get(&globalContext(), /*width=*/1);
- auto f = makeFunction("operator_and", {}, {i1Type, i1Type});
-
- OpBuilder builder(f.getBody());
- ScopedContext scope(builder, f.getLoc());
-
- using op::operator&&;
- using op::negate;
- Value lhs(f.getArgument(0));
- Value rhs(f.getArgument(1));
- negate(lhs && rhs);
-
- // clang-format off
- // CHECK-LABEL: @operator_and
- // CHECK: [[ARG0:%.*]]: i1, [[ARG1:%.*]]: i1
- // CHECK: [[AND:%.*]] = and [[ARG0]], [[ARG1]]
- // CHECK: [[TRUE:%.*]] = constant true
- // CHECK: subi [[TRUE]], [[AND]] : i1
- // clang-format on
- f.print(llvm::outs(), OpPrintingFlags().useLocalScope());
- f.erase();
-}
-
-TEST_FUNC(divis_op_i32) {
- using namespace edsc::op;
- auto f = makeFunction("divis_op", {}, {});
-
- OpBuilder builder(f.getBody());
- ScopedContext scope(builder, f.getLoc());
- auto i32Type = builder.getI32Type();
- std_divis(std_constant_int(10, i32Type), std_constant_int(2, i32Type));
-
- // clang-format off
- // CHECK-LABEL: @divis_op
- // CHECK-DAG: {{.*}} = constant 10
- // CHECK-DAG: {{.*}} = constant 2
- // CHECK-NEXT: {{.*}} = divi_signed
- // clang-format on
- f.print(llvm::outs(), OpPrintingFlags().useLocalScope());
- f.erase();
-}
-
-TEST_FUNC(diviu_op_i32) {
- using namespace edsc::op;
- auto f = makeFunction("diviu_op", {}, {});
-
- OpBuilder builder(f.getBody());
- ScopedContext scope(builder, f.getLoc());
- auto i32Type = builder.getI32Type();
- std_diviu(std_constant_int(10, i32Type), std_constant_int(2, i32Type));
-
- // clang-format off
- // CHECK-LABEL: @diviu_op
- // CHECK-DAG: {{.*}} = constant 10
- // CHECK-DAG: {{.*}} = constant 2
- // CHECK-NEXT: {{.*}} = divi_unsigned
- // clang-format on
- f.print(llvm::outs(), OpPrintingFlags().useLocalScope());
- f.erase();
-}
-
-TEST_FUNC(fpext_f32_f64) {
- using namespace edsc::op;
- auto f = makeFunction("fpext", {}, {});
-
- OpBuilder builder(f.getBody());
- ScopedContext scope(builder, f.getLoc());
- auto f32Type = builder.getF32Type();
- auto f64Type = builder.getF64Type();
- std_fpext(std_constant_float(llvm::APFloat(10.0f), f32Type), f64Type);
-
- // clang-format off
- // CHECK-LABEL: @fpext
- // CHECK: {{.*}} = constant 1.0
- // CHECK-NEXT: {{.*}} = fpext
- // clang-format on
- f.print(llvm::outs(), OpPrintingFlags().useLocalScope());
- f.erase();
-}
-
-TEST_FUNC(fptrunc_f32_bf16) {
- using namespace edsc::op;
- auto f = makeFunction("fptrunc", {}, {});
-
- OpBuilder builder(f.getBody());
- ScopedContext scope(builder, f.getLoc());
- auto f32Type = builder.getF32Type();
- auto bf16Type = builder.getBF16Type();
- std_fptrunc(std_constant_float(llvm::APFloat(10.0f), f32Type), bf16Type);
-
- // clang-format off
- // CHECK-LABEL: @fptrunc
- // CHECK: {{.*}} = constant 1.0
- // CHECK-NEXT: {{.*}} = fptrunc
- // clang-format on
- f.print(llvm::outs(), OpPrintingFlags().useLocalScope());
- f.erase();
-}
-
-TEST_FUNC(select_op_i32) {
- using namespace edsc::op;
- auto i32Type = IntegerType::get(&globalContext(), 32);
- auto memrefType = MemRefType::get(
- {ShapedType::kDynamicSize, ShapedType::kDynamicSize}, i32Type, {}, 0);
- auto f = makeFunction("select_op", {}, {memrefType});
-
- OpBuilder builder(f.getBody());
- ScopedContext scope(builder, f.getLoc());
- Value zero = std_constant_index(0), one = std_constant_index(1);
- MemRefBoundsCapture vA(f.getArgument(0));
- AffineIndexedValue A(f.getArgument(0));
- affineLoopNestBuilder({zero, zero}, {one, one}, {1, 1}, [&](ValueRange ivs) {
- using namespace edsc::op;
- Value i = ivs[0], j = ivs[1];
- std_select(eq(i, zero), A(zero, zero), A(i, j));
- std_select(ne(i, zero), A(zero, zero), A(i, j));
- std_select(slt(i, zero), A(zero, zero), A(i, j));
- std_select(sle(i, zero), A(zero, zero), A(i, j));
- std_select(sgt(i, zero), A(zero, zero), A(i, j));
- std_select(sge(i, zero), A(zero, zero), A(i, j));
- std_select(ult(i, zero), A(zero, zero), A(i, j));
- std_select(ule(i, zero), A(zero, zero), A(i, j));
- std_select(ugt(i, zero), A(zero, zero), A(i, j));
- std_select(uge(i, zero), A(zero, zero), A(i, j));
- });
-
- // clang-format off
- // CHECK-LABEL: @select_op
- // CHECK: affine.for %{{.*}} = 0 to 1 {
- // CHECK-NEXT: affine.for %{{.*}} = 0 to 1 {
- // CHECK-DAG: {{.*}} = cmpi eq
- // CHECK-DAG: {{.*}} = affine.load
- // CHECK-DAG: {{.*}} = affine.load
- // CHECK-NEXT: {{.*}} = select
- // CHECK-DAG: {{.*}} = cmpi ne
- // CHECK-DAG: {{.*}} = affine.load
- // CHECK-DAG: {{.*}} = affine.load
- // CHECK-NEXT: {{.*}} = select
- // CHECK-DAG: {{.*}} = cmpi slt
- // CHECK-DAG: {{.*}} = affine.load
- // CHECK-DAG: {{.*}} = affine.load
- // CHECK-NEXT: {{.*}} = select
- // CHECK-DAG: {{.*}} = cmpi sle
- // CHECK-DAG: {{.*}} = affine.load
- // CHECK-DAG: {{.*}} = affine.load
- // CHECK-NEXT: {{.*}} = select
- // CHECK-DAG: {{.*}} = cmpi sgt
- // CHECK-DAG: {{.*}} = affine.load
- // CHECK-DAG: {{.*}} = affine.load
- // CHECK-NEXT: {{.*}} = select
- // CHECK-DAG: {{.*}} = cmpi sge
- // CHECK-DAG: {{.*}} = affine.load
- // CHECK-DAG: {{.*}} = affine.load
- // CHECK-NEXT: {{.*}} = select
- // CHECK-DAG: {{.*}} = cmpi ult
- // CHECK-DAG: {{.*}} = affine.load
- // CHECK-DAG: {{.*}} = affine.load
- // CHECK-NEXT: {{.*}} = select
- // CHECK-DAG: {{.*}} = cmpi ule
- // CHECK-DAG: {{.*}} = affine.load
- // CHECK-DAG: {{.*}} = affine.load
- // CHECK-NEXT: {{.*}} = select
- // CHECK-DAG: {{.*}} = cmpi ugt
- // CHECK-DAG: {{.*}} = affine.load
- // CHECK-DAG: {{.*}} = affine.load
- // CHECK-NEXT: {{.*}} = select
- // CHECK-DAG: {{.*}} = cmpi uge
- // CHECK-DAG: {{.*}} = affine.load
- // CHECK-DAG: {{.*}} = affine.load
- // CHECK-NEXT: {{.*}} = select
- // clang-format on
- f.print(llvm::outs(), OpPrintingFlags().useLocalScope());
- f.erase();
-}
-
-TEST_FUNC(select_op_f32) {
- auto f32Type = FloatType::getF32(&globalContext());
- auto memrefType = MemRefType::get(
- {ShapedType::kDynamicSize, ShapedType::kDynamicSize}, f32Type, {}, 0);
- auto f = makeFunction("select_op", {}, {memrefType, memrefType});
-
- OpBuilder builder(f.getBody());
- ScopedContext scope(builder, f.getLoc());
- // clang-format off
- Value zero = std_constant_index(0), one = std_constant_index(1);
- MemRefBoundsCapture vA(f.getArgument(0)), vB(f.getArgument(1));
- AffineIndexedValue A(f.getArgument(0)), B(f.getArgument(1));
- affineLoopNestBuilder({zero, zero}, {one, one}, {1, 1}, [&](ValueRange ivs) {
- using namespace edsc::op;
- Value i = ivs[0], j = ivs[1];
- std_select(eq(B(i, j), B(i + one, j)), A(zero, zero), A(i, j));
- std_select(ne(B(i, j), B(i + one, j)), A(zero, zero), A(i, j));
- std_select(sge(B(i, j), B(i + one, j)), A(zero, zero), A(i, j));
- std_select(sle(B(i, j), B(i + one, j)), A(zero, zero), A(i, j));
- std_select(slt(B(i, j), B(i + one, j)), A(zero, zero), A(i, j));
- std_select(sgt(B(i, j), B(i + one, j)), A(zero, zero), A(i, j));
- std_select(uge(B(i, j), B(i + one, j)), A(zero, zero), A(i, j));
- std_select(ule(B(i, j), B(i + one, j)), A(zero, zero), A(i, j));
- std_select(ult(B(i, j), B(i + one, j)), A(zero, zero), A(i, j));
- std_select(ugt(B(i, j), B(i + one, j)), A(zero, zero), A(i, j));
- });
-
- // clang-format off
- // CHECK-LABEL: @select_op
- // CHECK: affine.for %{{.*}} = 0 to 1 {
- // CHECK-NEXT: affine.for %{{.*}} = 0 to 1 {
- // CHECK-DAG: cmpf oeq
- // CHECK-DAG: affine.load
- // CHECK-DAG: affine.load
- // CHECK-DAG: affine.load
- // CHECK-DAG: affine.load
- // CHECK-DAG: affine.apply
- // CHECK-NEXT: select
- // CHECK-DAG: cmpf one
- // CHECK-DAG: affine.load
- // CHECK-DAG: affine.load
- // CHECK-DAG: affine.load
- // CHECK-DAG: affine.load
- // CHECK-DAG: affine.apply
- // CHECK-NEXT: select
- // CHECK-DAG: cmpf oge
- // CHECK-DAG: affine.load
- // CHECK-DAG: affine.load
- // CHECK-DAG: affine.load
- // CHECK-DAG: affine.load
- // CHECK-DAG: affine.apply
- // CHECK-NEXT: select
- // CHECK-DAG: cmpf ole
- // CHECK-DAG: affine.load
- // CHECK-DAG: affine.load
- // CHECK-DAG: affine.load
- // CHECK-DAG: affine.load
- // CHECK-DAG: affine.apply
- // CHECK-NEXT: select
- // CHECK-DAG: cmpf olt
- // CHECK-DAG: affine.load
- // CHECK-DAG: affine.load
- // CHECK-DAG: affine.load
- // CHECK-DAG: affine.load
- // CHECK-DAG: affine.apply
- // CHECK-NEXT: select
- // CHECK-DAG: cmpf ogt
- // CHECK-DAG: affine.load
- // CHECK-DAG: affine.load
- // CHECK-DAG: affine.load
- // CHECK-DAG: affine.load
- // CHECK-DAG: affine.apply
- // CHECK-NEXT: select
- // CHECK-DAG: cmpf oge
- // CHECK-DAG: affine.load
- // CHECK-DAG: affine.load
- // CHECK-DAG: affine.load
- // CHECK-DAG: affine.load
- // CHECK-DAG: affine.apply
- // CHECK-NEXT: select
- // CHECK-DAG: cmpf ole
- // CHECK-DAG: affine.load
- // CHECK-DAG: affine.load
- // CHECK-DAG: affine.load
- // CHECK-DAG: affine.load
- // CHECK-DAG: affine.apply
- // CHECK-NEXT: select
- // CHECK-DAG: cmpf olt
- // CHECK-DAG: affine.load
- // CHECK-DAG: affine.load
- // CHECK-DAG: affine.load
- // CHECK-DAG: affine.load
- // CHECK-DAG: affine.apply
- // CHECK-NEXT: select
- // CHECK-DAG: cmpf ogt
- // CHECK-DAG: affine.load
- // CHECK-DAG: affine.load
- // CHECK-DAG: affine.load
- // CHECK-DAG: affine.load
- // CHECK-DAG: affine.apply
- // CHECK-NEXT: select
- // clang-format on
- f.print(llvm::outs(), OpPrintingFlags().useLocalScope());
- f.erase();
-}
-
-// Inject an EDSC-constructed computation to exercise imperfectly nested 2-d
-// tiling.
-TEST_FUNC(tile_2d) {
- auto memrefType =
- MemRefType::get({ShapedType::kDynamicSize, ShapedType::kDynamicSize,
- ShapedType::kDynamicSize},
- FloatType::getF32(&globalContext()), {}, 0);
- auto f = makeFunction("tile_2d", {}, {memrefType, memrefType, memrefType});
-
- OpBuilder builder(f.getBody());
- ScopedContext scope(builder, f.getLoc());
- Value zero = std_constant_index(0);
- MemRefBoundsCapture vA(f.getArgument(0)), vB(f.getArgument(1)),
- vC(f.getArgument(2));
- AffineIndexedValue A(f.getArgument(0)), B(f.getArgument(1)),
- C(f.getArgument(2));
- Value i, j, k1, k2;
- Value M(vC.ub(0)), N(vC.ub(1)), O(vC.ub(2));
-
- // clang-format off
- using namespace edsc::op;
- affineLoopNestBuilder({zero, zero}, {M, N}, {1, 1}, [&](ValueRange ivs) {
- i = ivs[0];
- j = ivs[1];
- affineLoopBuilder(zero, O, 1, [&](Value k) {
- k1 = k;
- C(i, j, k1) = A(i, j, k1) + B(i, j, k1);
- });
- affineLoopBuilder(zero, O, 1, [&](Value k) {
- k2 = k;
- C(i, j, k2) = A(i, j, k2) + B(i, j, k2);
- });
- });
- // clang-format on
-
- auto li = getForInductionVarOwner(i), lj = getForInductionVarOwner(j),
- lk1 = getForInductionVarOwner(k1), lk2 = getForInductionVarOwner(k2);
- auto indicesL1 = mlir::tile({li, lj}, {512, 1024}, {lk1, lk2});
- auto lii1 = indicesL1[0][0], ljj1 = indicesL1[1][0];
- mlir::tile({ljj1, lii1}, {32, 16}, ljj1);
-
- // clang-format off
- // CHECK-LABEL: func @tile_2d
- // CHECK: %[[ZERO:.*]] = constant 0 : index
- // CHECK: %[[M:[0-9]+]] = memref.dim %arg2, %c0{{[_0-9]*}} : memref<?x?x?xf32>
- // CHECK: %[[N:[0-9]+]] = memref.dim %arg2, %c1{{[_0-9]*}} : memref<?x?x?xf32>
- // CHECK: %[[P:[0-9]+]] = memref.dim %arg2, %c2{{[_0-9]*}} : memref<?x?x?xf32>
- // CHECK: affine.for %{{.*}} = affine_map<(d0) -> (d0)>(%[[ZERO]]) to affine_map<(d0) -> (d0)>(%[[M]]) step 512 {
- // CHECK-NEXT: affine.for %{{.*}} = affine_map<(d0) -> (d0)>(%[[ZERO]]) to affine_map<(d0) -> (d0)>(%[[N]]) step 1024 {
- // CHECK-NEXT: affine.for %{{.*}} = affine_map<(d0) -> (d0)>(%[[ZERO]]) to affine_map<(d0) -> (d0)>(%[[P]]) {
- // CHECK-NEXT: affine.for %{{.*}} = max affine_map<(d0) -> (0, d0)>(%{{.*}}) to min affine_map<(d0)[s0] -> (s0, d0 + 512)>(%{{.*}})[%[[M]]] step 16 {
- // CHECK-NEXT: affine.for %{{.*}} = max affine_map<(d0) -> (0, d0)>(%{{.*}}) to min affine_map<(d0)[s0] -> (s0, d0 + 1024)>(%{{.*}})[%[[N]]] step 32 {
- // CHECK-NEXT: affine.for %{{.*}} = max affine_map<(d0, d1) -> (0, d0, d1)>(%{{.*}}, %{{.*}}) to min affine_map<(d0, d1)[s0] -> (s0, d0 + 1024, d1 + 32)>(%{{.*}}, %{{.*}})[%[[N]]] {
- // CHECK-NEXT: affine.for %{{.*}} = max affine_map<(d0, d1) -> (0, d0, d1)>(%{{.*}}, %{{.*}}) to min affine_map<(d0, d1)[s0] -> (s0, d0 + 512, d1 + 16)>(%{{.*}}, %{{.*}})[%[[M]]] {
- // CHECK-NEXT: {{.*}} = affine.load {{.*}}[%{{.*}}, %{{.*}}, %{{.*}}] : memref<?x?x?xf32>
- // CHECK-NEXT: {{.*}} = affine.load {{.*}}[%{{.*}}, %{{.*}}, %{{.*}}] : memref<?x?x?xf32>
- // CHECK-NEXT: {{.*}} = addf {{.*}}, {{.*}} : f32
- // CHECK-NEXT: affine.store {{.*}}, {{.*}}[%{{.*}}, %{{.*}}, %{{.*}}] : memref<?x?x?xf32>
- // CHECK: }
- // CHECK-NEXT: }
- // CHECK-NEXT: }
- // CHECK-NEXT: }
- // CHECK-NEXT: }
- // CHECK-NEXT: affine.for %{{.*}} = affine_map<(d0) -> (d0)>(%[[ZERO]]) to affine_map<(d0) -> (d0)>(%[[P]]) {
- // CHECK-NEXT: affine.for %{{.*}} = max affine_map<(d0) -> (0, d0)>(%{{.*}}) to min affine_map<(d0)[s0] -> (s0, d0 + 512)>(%{{.*}})[%[[M]]] {
- // CHECK-NEXT: affine.for %{{.*}} = max affine_map<(d0) -> (0, d0)>(%{{.*}}) to min affine_map<(d0)[s0] -> (s0, d0 + 1024)>(%{{.*}})[%[[N]]] {
- // CHECK-NEXT: {{.*}} = affine.load {{.*}}[%{{.*}}, %{{.*}}, %{{.*}}] : memref<?x?x?xf32>
- // CHECK-NEXT: {{.*}} = affine.load {{.*}}[%{{.*}}, %{{.*}}, %{{.*}}] : memref<?x?x?xf32>
- // CHECK-NEXT: {{.*}}= addf {{.*}}, {{.*}} : f32
- // CHECK-NEXT: affine.store {{.*}}, {{.*}}[%{{.*}}, %{{.*}}, %{{.*}}] : memref<?x?x?xf32>
- // clang-format on
- f.print(llvm::outs(), OpPrintingFlags().useLocalScope());
- f.erase();
-}
-
-// Exercise StdIndexedValue for loads and stores.
-TEST_FUNC(indirect_access) {
- using namespace edsc::op;
- auto memrefType = MemRefType::get({ShapedType::kDynamicSize},
- FloatType::getF32(&globalContext()), {}, 0);
- auto f = makeFunction("indirect_access", {},
- {memrefType, memrefType, memrefType, memrefType});
-
- OpBuilder builder(f.getBody());
- ScopedContext scope(builder, f.getLoc());
- Value zero = std_constant_index(0);
- MemRefBoundsCapture vC(f.getArgument(2));
- AffineIndexedValue B(f.getArgument(1)), D(f.getArgument(3));
- MemRefIndexedValue A(f.getArgument(0)), C(f.getArgument(2));
- Value N(vC.ub(0));
-
- // clang-format off
- affineLoopBuilder(zero, N, 1, [&](Value i) {
- C((Value)D(i)) = A((Value)B(i));
- });
- // clang-format on
-
- // clang-format off
- // CHECK-LABEL: func @indirect_access
- // CHECK-SAME: (%[[ARG0:.*]]: memref<?xf32>, %[[ARG1:.*]]: memref<?xf32>, %[[ARG2:.*]]: memref<?xf32>, %[[ARG3:.*]]: memref<?xf32>)
- // CHECK-DAG: [[B:%.*]] = affine.load %[[ARG1]]
- // CHECK-DAG: [[D:%.*]] = affine.load %[[ARG3]]
- // CHECK: load %{{.*}}{{\[}}[[B]]{{\]}}
- // CHECK: store %{{.*}}, %{{.*}}{{\[}}[[D]]{{\]}}
- // clang-format on
- f.print(llvm::outs(), OpPrintingFlags().useLocalScope());
- f.erase();
-}
-
-// Exercise affine loads and stores build with empty maps.
-TEST_FUNC(empty_map_load_store) {
- using namespace edsc::op;
- auto memrefType =
- MemRefType::get({}, FloatType::getF32(&globalContext()), {}, 0);
- auto f = makeFunction("empty_map_load_store", {},
- {memrefType, memrefType, memrefType, memrefType});
-
- OpBuilder builder(f.getBody());
- ScopedContext scope(builder, f.getLoc());
- Value zero = std_constant_index(0);
- Value one = std_constant_index(1);
- AffineIndexedValue input(f.getArgument(0)), res(f.getArgument(1));
-
- // clang-format off
- affineLoopBuilder(zero, one, 1, [&](Value) {
- res() = input();
- });
- // clang-format on
-
- // clang-format off
- // CHECK-LABEL: func @empty_map_load_store(
- // CHECK: [[A:%.*]] = affine.load %{{.*}}[]
- // CHECK: affine.store [[A]], %{{.*}}[]
- // clang-format on
- f.print(llvm::outs(), OpPrintingFlags().useLocalScope());
- f.erase();
-}
-
-// clang-format off
-// CHECK-LABEL: func @affine_if_op
-// CHECK: affine.if affine_set<([[d0:.*]], [[d1:.*]]){{\[}}[[s0:.*]], [[s1:.*]]{{\]}}
-// CHECK-NOT: else
-// CHECK: affine.if affine_set<([[d0:.*]], [[d1:.*]]){{\[}}[[s0:.*]], [[s1:.*]]{{\]}}
-// CHECK-NEXT: } else {
-// clang-format on
-TEST_FUNC(affine_if_op) {
- using namespace edsc::op;
- auto f32Type = FloatType::getF32(&globalContext());
- auto memrefType = MemRefType::get(
- {ShapedType::kDynamicSize, ShapedType::kDynamicSize}, f32Type, {}, 0);
- auto f = makeFunction("affine_if_op", {}, {memrefType});
-
- OpBuilder builder(f.getBody());
- ScopedContext scope(builder, f.getLoc());
-
- Value zero = std_constant_index(0), ten = std_constant_index(10);
-
- SmallVector<bool, 4> isEq = {false, false, false, false};
- SmallVector<AffineExpr, 4> affineExprs = {
- builder.getAffineDimExpr(0), // d0 >= 0
- builder.getAffineDimExpr(1), // d1 >= 0
- builder.getAffineSymbolExpr(0), // s0 >= 0
- builder.getAffineSymbolExpr(1) // s1 >= 0
- };
- auto intSet = IntegerSet::get(2, 2, affineExprs, isEq);
-
- SmallVector<Value, 4> affineIfArgs = {zero, zero, ten, ten};
- intrinsics::affine_if(intSet, affineIfArgs, /*withElseRegion=*/false);
- intrinsics::affine_if(intSet, affineIfArgs, /*withElseRegion=*/true);
-
- f.print(llvm::outs(), OpPrintingFlags().useLocalScope());
- f.erase();
-}
-
-// clang-format off
-// CHECK-LABEL: func @linalg_generic_pointwise
-// CHECK: linalg.generic {
-// CHECK-SAME: indexing_maps = [affine_map<(d0, d1) -> (d0, d1)>, affine_map<(d0, d1) -> (d0, d1)>, affine_map<(d0, d1) -> (d0, d1)>],
-// CHECK-SAME: iterator_types = ["parallel", "parallel"]}
-// CHECK-SAME: ins({{.*}}memref<?x?xf32>, memref<?x?xf32>)
-// CHECK-SAME: outs({{.*}}memref<?x?xf32>)
-// CHECK: addf
-// CHECK: linalg.generic {
-// CHECK-SAME: indexing_maps = [affine_map<(d0, d1) -> (d0, d1)>, affine_map<(d0, d1) -> (d0, d1)>, affine_map<(d0, d1) -> (d0, d1)>],
-// CHECK-SAME: iterator_types = ["parallel", "parallel"]}
-// CHECK-SAME: ins({{.*}}memref<?x?xf32>, memref<?x?xf32>)
-// CHECK-SAME: outs({{.*}}memref<?x?xf32>)
-// CHECK: cmpf ogt
-// CHECK: select
-// CHECK: linalg.generic {
-// CHECK-SAME: indexing_maps = [affine_map<(d0, d1) -> (d0, d1)>, affine_map<(d0, d1) -> (d0, d1)>],
-// CHECK-SAME: iterator_types = ["parallel", "parallel"]}
-// CHECK-SAME: ins(%{{[a-z0-9]*}} : memref<?x?xf32>)
-// CHECK-SAME: outs(%{{[a-z0-9]*}} : memref<?x?xf32>)
-// CHECK: tanh
-// clang-format on
-TEST_FUNC(linalg_generic_pointwise_test) {
- using namespace edsc;
- using namespace edsc::ops;
-
- auto f32Type = FloatType::getF32(&globalContext());
- auto memrefType = MemRefType::get(
- {ShapedType::kDynamicSize, ShapedType::kDynamicSize}, f32Type, {}, 0);
- auto f = makeFunction("linalg_generic_pointwise", {},
- {memrefType, memrefType, memrefType});
-
- OpBuilder builder(f.getBody());
- ScopedContext scope(builder, f.getLoc());
- Value A(f.getArgument(0)), B(f.getArgument(1)), C(f.getArgument(2));
- AffineExpr i, j;
- bindDims(&globalContext(), i, j);
- StructuredIndexed SA(A), SB(B), SC(C);
- linalg_generic_pointwise_add(SA({i, j}), SB({i, j}), SC({i, j}));
- linalg_generic_pointwise_max(SA({i, j}), SB({i, j}), SC({i, j}));
- linalg_generic_pointwise_tanh(SA({i, j}), SC({i, j}));
-
- f.print(llvm::outs(), OpPrintingFlags().useLocalScope());
- f.erase();
-}
-
-// clang-format off
-// CHECK-LABEL: func @linalg_generic_matmul
-// CHECK: linalg.generic {
-// CHECK-SAME: indexing_maps = [affine_map<(d0, d1, d2) -> (d0, d2)>, affine_map<(d0, d1, d2) -> (d2, d1)>, affine_map<(d0, d1, d2) -> (d0, d1)>],
-// CHECK-SAME: iterator_types = ["parallel", "parallel", "reduction"]}
-// CHECK-SAME: ins(%{{[a-z0-9]*}}, %{{[a-z0-9]*}} : memref<?x?xf32>, memref<?x?xf32>)
-// CHECK-SAME: outs(%{{[a-z0-9]*}} : memref<?x?xf32>)
-/// CHECK: ^bb0(%[[a0:.*]]: f32, %[[a1:.*]]: f32, %[[a2:.*]]: f32):
-// CHECK: %[[a3:.*]] = mulf %[[a0]], %[[a1]] : f32
-// CHECK: %[[a4:.*]] = addf %[[a2]], %[[a3]] : f32
-// CHECK: linalg.yield %[[a4]] : f32
-// CHECK: }
-// clang-format on
-TEST_FUNC(linalg_generic_matmul_test) {
- using namespace edsc;
- using namespace edsc::ops;
-
- auto f32Type = FloatType::getF32(&globalContext());
- auto memrefType = MemRefType::get(
- {ShapedType::kDynamicSize, ShapedType::kDynamicSize}, f32Type, {}, 0);
- auto f = makeFunction("linalg_generic_matmul", {},
- {memrefType, memrefType, memrefType});
-
- OpBuilder builder(f.getBody());
- ScopedContext scope(builder, f.getLoc());
- linalg_generic_matmul(f.getArguments());
-
- f.print(llvm::outs(), OpPrintingFlags().useLocalScope());
- f.erase();
-}
-
-// clang-format off
-// CHECK-LABEL: func @linalg_generic_conv_nhwc
-// CHECK: linalg.generic {
-// CHECK-SAME: indexing_maps = [affine_map<(d0, d1, d2, d3, d4, d5, d6) -> (d0, d2 * 3 + d4 * 5, d3 * 4 + d5 * 6, d6)>,
-// CHECK-SAME: affine_map<(d0, d1, d2, d3, d4, d5, d6) -> (d4, d5, d6, d1)>,
-// CHECK-SAME: affine_map<(d0, d1, d2, d3, d4, d5, d6) -> (d0, d2, d3, d1)>],
-// CHECK-SAME: iterator_types = ["parallel", "parallel", "parallel", "parallel", "reduction", "reduction", "reduction"]}
-// CHECK-SAME: ins(%{{[a-z0-9]*}}, %{{[a-z0-9]*}} : memref<?x?x?x?xf32>, memref<?x?x?x?xf32>)
-// CHECK-SAME: outs(%{{[a-z0-9]*}} : memref<?x?x?x?xf32>)
-/// CHECK: ^bb0(%[[a0:.*]]: f32, %[[a1:.*]]: f32, %[[a2:.*]]: f32):
-// CHECK: %[[a3:.*]] = mulf %[[a0]], %[[a1]] : f32
-// CHECK: %[[a4:.*]] = addf %[[a2]], %[[a3]] : f32
-// CHECK: linalg.yield %[[a4]] : f32
-// CHECK: }
-// clang-format on
-TEST_FUNC(linalg_generic_conv_nhwc) {
- using namespace edsc;
- using namespace edsc::ops;
-
- auto f32Type = FloatType::getF32(&globalContext());
- auto memrefType =
- MemRefType::get({ShapedType::kDynamicSize, ShapedType::kDynamicSize,
- ShapedType::kDynamicSize, ShapedType::kDynamicSize},
- f32Type, {}, 0);
- auto f = makeFunction("linalg_generic_conv_nhwc", {},
- {memrefType, memrefType, memrefType});
-
- OpBuilder builder(f.getBody());
- ScopedContext scope(builder, f.getLoc());
- linalg_generic_conv_nhwc(f.getArguments(),
- /*strides=*/{3, 4}, /*dilations=*/{5, 6});
-
- f.print(llvm::outs(), OpPrintingFlags().useLocalScope());
- f.erase();
-}
-
-// clang-format off
-// CHECK-LABEL: func @linalg_generic_dilated_conv_nhwc
-// CHECK: linalg.generic {
-// CHECK-SAME: indexing_maps = [affine_map<(d0, d1, d2, d3, d4, d5, d6) -> (d0, d3 * 3 + d5 * 5, d4 * 4 + d6 * 6, d2)>,
-// CHECK-SAME: affine_map<(d0, d1, d2, d3, d4, d5, d6) -> (d5, d6, d2, d1)>,
-// CHECK-SAME: affine_map<(d0, d1, d2, d3, d4, d5, d6) -> (d0, d3, d4, d1 + d2 * 7)>],
-// CHECK-SAME: iterator_types = ["parallel", "parallel", "parallel", "parallel", "parallel", "reduction", "reduction"]}
-// CHECK-SAME: ins(%{{[a-z0-9]*}}, %{{[a-z0-9]*}} : memref<?x?x?x?xf32>, memref<?x?x?x?xf32>)
-// CHECK-SAME: outs(%{{[a-z0-9]*}} : memref<?x?x?x?xf32>)
-// CHECK: ^bb0(%[[a0:.*]]: f32, %[[a1:.*]]: f32, %[[a2:.*]]: f32):
-// CHECK: %[[a3:.*]] = mulf %[[a0]], %[[a1]] : f32
-// CHECK: %[[a4:.*]] = addf %[[a2]], %[[a3]] : f32
-// CHECK: linalg.yield %[[a4]] : f32
-// CHECK: }
-// clang-format on
-TEST_FUNC(linalg_generic_dilated_conv_nhwc) {
- using namespace edsc;
- using namespace edsc::ops;
-
- auto f32Type = FloatType::getF32(&globalContext());
- auto memrefType =
- MemRefType::get({ShapedType::kDynamicSize, ShapedType::kDynamicSize,
- ShapedType::kDynamicSize, ShapedType::kDynamicSize},
- f32Type, {}, 0);
- auto f = makeFunction("linalg_generic_dilated_conv_nhwc", {},
- {memrefType, memrefType, memrefType});
-
- OpBuilder builder(f.getBody());
- ScopedContext scope(builder, f.getLoc());
- linalg_generic_dilated_conv_nhwc(f.getArguments(),
- /*depth_multiplier=*/7,
- /*strides=*/{3, 4}, /*dilations=*/{5, 6});
-
- f.print(llvm::outs(), OpPrintingFlags().useLocalScope());
- f.erase();
-}
-
-// clang-format off
-// CHECK-LABEL: func @linalg_metadata_ops
-// CHECK: linalg.reshape {{.*}} {{\[}}[0, 1], [2]] : memref<4x8x16xf32> into memref<32x16xf32>
-// CHECK: linalg.reshape {{.*}} {{\[}}[0, 1], [2]] : memref<32x16xf32> into memref<4x8x16xf32>
-// clang-format on
-TEST_FUNC(linalg_metadata_ops) {
- using linalg::ReassociationExprs;
-
- auto f32Type = FloatType::getF32(&globalContext());
- auto memrefType = MemRefType::get({4, 8, 16}, f32Type, {}, 0);
- auto f = makeFunction("linalg_metadata_ops", {}, {memrefType});
-
- OpBuilder builder(f.getBody());
- ScopedContext scope(builder, f.getLoc());
- AffineExpr i, j, k;
- bindDims(&globalContext(), i, j, k);
- Value v(f.getArgument(0));
- SmallVector<ReassociationExprs, 2> maps = {ReassociationExprs({i, j}),
- ReassociationExprs({k})};
- auto reshaped = linalg_reshape(v, maps);
- linalg_reshape(memrefType, reshaped, maps);
-
- f.print(llvm::outs(), OpPrintingFlags().useLocalScope());
- f.erase();
-}
-
-// clang-format off
-// CHECK-LABEL: func @linalg_tensors
-// CHECK: linalg.generic {
-// CHECK-SAME: indexing_maps = [affine_map<(d0, d1) -> (d0, d1)>, affine_map<(d0, d1) -> (d0, d1)>, affine_map<(d0, d1) -> (d0, d1)>],
-// CHECK-SAME: iterator_types = ["parallel", "parallel"]}
-// CHECK-SAME: ins(%{{[a-z0-9]*}}, %{{[a-z0-9]*}} : tensor<?x?xf32>, memref<?x?xf32>)
-// CHECK: addf
-// CHECK: } -> tensor<?x?xf32>
-// CHECK: linalg.generic {
-// CHECK-SAME: indexing_maps = [affine_map<(d0, d1) -> (d0, d1)>, affine_map<(d0, d1) -> (d0, d1)>, affine_map<(d0, d1) -> (d0, d1)>],
-// CHECK-SAME: iterator_types = ["parallel", "parallel"]}
-// CHECK-SAME: ins(%{{[a-z0-9]*}}, %{{[a-z0-9]*}} : tensor<?x?xf32>, tensor<?x?xf32>)
-// CHECK: cmpf ogt
-// CHECK: select
-// CHECK: } -> tensor<?x?xf32>
-// CHECK: linalg.generic {
-// CHECK-SAME: indexing_maps = [affine_map<(d0, d1) -> (d0, d1)>, affine_map<(d0, d1) -> (d0, d1)>],
-// CHECK-SAME: iterator_types = ["parallel", "parallel"]}
-// CHECK-SAME: ins(%{{[a-z0-9]*}} : tensor<?x?xf32>)
-// CHECK: tanh
-// CHECK: } -> tensor<?x?xf32>
-// CHECK: linalg.generic {
-// CHECK-SAME: indexing_maps = [affine_map<(d0, d1, d2) -> (d0, d2)>,
-// CHECK-SAME: affine_map<(d0, d1, d2) -> (d2, d1)>,
-// CHECK-SAME: affine_map<(d0, d1, d2) -> (d0, d1)>],
-// CHECK-SAME: iterator_types = ["parallel", "parallel", "reduction"]}
-// CHECK-SAME: ins(%{{[a-z0-9]*}}, %{{[a-z0-9]*}} : tensor<?x?xf32>, memref<?x?xf32>)
-// CHECK: mulf
-// CHECK: } -> tensor<?x?xf32>
-// CHECK: linalg.generic {
-// CHECK-SAME: indexing_maps = [affine_map<(d0, d1, d2) -> (d0, d2)>,
-// CHECK-SAME: affine_map<(d0, d1, d2) -> (d2, d1)>,
-// CHECK-SAME: affine_map<(d0, d1, d2) -> (d0, d1)>],
-// CHECK-SAME: iterator_types = ["parallel", "parallel", "reduction"]
-// CHECK-SAME: ins(%{{[a-z0-9]*}}, %{{[a-z0-9]*}} : tensor<?x?xf32>, memref<?x?xf32>)
-// CHECK-SAME: outs(%{{[a-z0-9]*}} : tensor<?x?xf32>)
-// CHECK: mulf
-// CHECK: addf
-// CHECK: } -> tensor<?x?xf32>
-// clang-format on
-TEST_FUNC(linalg_tensors_test) {
- using namespace edsc;
- using namespace edsc::ops;
-
- auto f32Type = FloatType::getF32(&globalContext());
- auto memrefType = MemRefType::get(
- {ShapedType::kDynamicSize, ShapedType::kDynamicSize}, f32Type, {}, 0);
- auto tensorType = RankedTensorType::get(
- {ShapedType::kDynamicSize, ShapedType::kDynamicSize}, f32Type);
- auto f =
- makeFunction("linalg_tensors", {}, {tensorType, memrefType, tensorType});
-
- OpBuilder builder(f.getBody());
- ScopedContext scope(builder, f.getLoc());
- Value A(f.getArgument(0)), B(f.getArgument(1)), C(f.getArgument(2));
- AffineExpr i, j;
- bindDims(&globalContext(), i, j);
- StructuredIndexed SA(A), SB(B), SC(C);
- Value added = linalg_generic_pointwise_add(SA({i, j}), SB({i, j}), SC({i, j}))
- ->getResult(0);
- Value maxed = linalg_generic_pointwise_max(
- SA({i, j}), StructuredIndexed(added)({i, j}), SC({i, j}))
- ->getResult(0);
- Value tanhed = linalg_generic_pointwise_tanh(StructuredIndexed(maxed)({i, j}),
- SC({i, j}))
- ->getResult(0);
- Value o1 = linalg_generic_matmul(A, B, tanhed, tensorType)->getResult(0);
- linalg_generic_matmul(A, B, o1, tensorType);
-
- f.print(llvm::outs(), OpPrintingFlags().useLocalScope());
- f.erase();
-}
-
-TEST_FUNC(vector_extractelement_op_i32) {
- using namespace edsc::op;
- auto f = makeFunction("vector_extractelement_op", {}, {});
-
- OpBuilder builder(f.getBody());
- ScopedContext scope(builder, f.getLoc());
- auto i32Type = builder.getI32Type();
- auto vectorType = VectorType::get(/*shape=*/{8}, i32Type);
- vector_extract_element(
- i32Type, std_constant(vectorType, builder.getI32VectorAttr({10})),
- std_constant_int(0, i32Type));
-
- // clang-format off
- // CHECK-LABEL: @vector_extractelement_op
- // CHECK-DAG: {{.*}} = constant dense<10>
- // CHECK-DAG: {{.*}} = constant 0
- // CHECK-NEXT: {{.*}} = vector.extractelement
- // clang-format on
- f.print(llvm::outs(), OpPrintingFlags().useLocalScope());
- f.erase();
-}
-
-// clang-format off
-// CHECK-LABEL: func @memref_vector_matmul_test(
-// CHECK-SAME: %[[A:.*]]: memref<?x?xvector<4x16xf32>>,
-// CHECK-SAME: %[[B:.*]]: memref<?x?xvector<16x8xf32>>,
-// CHECK-SAME: %[[C:.*]]: memref<?x?xvector<4x8xf32>>)
-// CHECK: linalg.generic {{{.*}}}
-// CHECK-SAME: ins(%[[A]], %[[B]] : memref<?x?xvector<4x16xf32>>, memref<?x?xvector<16x8xf32>>)
-// CHECK-SAME: outs(%[[C]] : memref<?x?xvector<4x8xf32>>)
-// CHECK: vector.contract{{.*}}[affine_map<(d0, d1, d2) -> (d0, d2)>,
-// CHECK-SAME: affine_map<(d0, d1, d2) -> (d2, d1)>,
-// CHECK-SAME: affine_map<(d0, d1, d2) -> (d0, d1)>],
-// CHECK-SAME: {{.*}}["parallel", "parallel", "reduction"]
-// clang-format on
-TEST_FUNC(memref_vector_matmul_test) {
- using namespace edsc;
- using namespace edsc::ops;
-
- int64_t M = 4, N = 8, K = 16;
- auto f32Type = FloatType::getF32(&globalContext());
- auto mkVectorType = VectorType::get({M, K}, f32Type);
- auto knVectorType = VectorType::get({K, N}, f32Type);
- auto mnVectorType = VectorType::get({M, N}, f32Type);
- auto typeA =
- MemRefType::get({ShapedType::kDynamicSize, ShapedType::kDynamicSize},
- mkVectorType, {}, 0);
- auto typeB =
- MemRefType::get({ShapedType::kDynamicSize, ShapedType::kDynamicSize},
- knVectorType, {}, 0);
- auto typeC =
- MemRefType::get({ShapedType::kDynamicSize, ShapedType::kDynamicSize},
- mnVectorType, {}, 0);
- auto f = makeFunction("memref_vector_matmul_test", {}, {typeA, typeB, typeC});
-
- OpBuilder builder(f.getBody());
- ScopedContext scope(builder, f.getLoc());
- Value A(f.getArgument(0)), B(f.getArgument(1)), C(f.getArgument(2));
- auto contractionBuilder = [](ValueRange args) {
- assert(args.size() == 3 && "expected 3 block arguments");
- (linalg_yield(vector_contraction_matmul(args[0], args[1], args[2])));
- };
- linalg_generic_matmul(A, B, C, contractionBuilder);
-
- f.print(llvm::outs(), OpPrintingFlags().useLocalScope());
- f.erase();
-}
-
-TEST_FUNC(builder_loop_for_yield) {
- auto indexType = IndexType::get(&globalContext());
- auto f32Type = FloatType::getF32(&globalContext());
- auto f = makeFunction("builder_loop_for_yield", {},
- {indexType, indexType, indexType, indexType});
-
- OpBuilder builder(f.getBody());
- ScopedContext scope(builder, f.getLoc());
- Value init0 = std_constant_float(llvm::APFloat(1.0f), f32Type);
- Value init1 = std_constant_float(llvm::APFloat(2.0f), f32Type);
- Value a(f.getArgument(0)), b(f.getArgument(1)), c(f.getArgument(2)),
- d(f.getArgument(3));
- using namespace edsc::op;
- auto results = loopNestBuilder(a - b, c + d, a, {init0, init1},
- [&](Value iv, ValueRange args) {
- Value sum = args[0] + args[1];
- return scf::ValueVector{args[1], sum};
- })
- .getResults();
- results[0] + results[1];
-
- // clang-format off
- // CHECK-LABEL: func @builder_loop_for_yield(%{{.*}}: index, %{{.*}}: index, %{{.*}}: index, %{{.*}}: index) {
- // CHECK: [[init0:%.*]] = constant
- // CHECK: [[init1:%.*]] = constant
- // CHECK-DAG: [[r0:%[0-9]+]] = affine.apply affine_map<()[s0, s1] -> (s0 - s1)>()[%{{.*}}, %{{.*}}]
- // CHECK-DAG: [[r1:%[0-9]+]] = affine.apply affine_map<()[s0, s1] -> (s0 + s1)>()[%{{.*}}, %{{.*}}]
- // CHECK-NEXT: [[res:%[0-9]+]]:2 = scf.for %{{.*}} = [[r0]] to [[r1]] step {{.*}} iter_args([[arg0:%.*]] = [[init0]], [[arg1:%.*]] = [[init1]]) -> (f32, f32) {
- // CHECK: [[sum:%[0-9]+]] = addf [[arg0]], [[arg1]] : f32
- // CHECK: scf.yield [[arg1]], [[sum]] : f32, f32
- // CHECK: addf [[res]]#0, [[res]]#1 : f32
- // clang-format on
-
- f.print(llvm::outs(), OpPrintingFlags().useLocalScope());
- f.erase();
-}
-
-int main() {
- RUN_TESTS();
- return 0;
-}
diff --git a/mlir/test/EDSC/lit.local.cfg b/mlir/test/EDSC/lit.local.cfg
deleted file mode 100644
index 81261555b424..000000000000
--- a/mlir/test/EDSC/lit.local.cfg
+++ /dev/null
@@ -1 +0,0 @@
-config.suffixes.add('.cpp')
More information about the Mlir-commits
mailing list