[Mlir-commits] [mlir] 367229e - [mlir][EDSC] Retire ValueHandle
Nicolas Vasilache
llvmlistbot at llvm.org
Thu Apr 23 08:05:00 PDT 2020
Author: Nicolas Vasilache
Date: 2020-04-23T11:01:16-04:00
New Revision: 367229e100eca714276253bf95a0dd3d084a9624
URL: https://github.com/llvm/llvm-project/commit/367229e100eca714276253bf95a0dd3d084a9624
DIFF: https://github.com/llvm/llvm-project/commit/367229e100eca714276253bf95a0dd3d084a9624.diff
LOG: [mlir][EDSC] Retire ValueHandle
The EDSC discussion [thread](https://llvm.discourse.group/t/evolving-builder-apis-based-on-lessons-learned-from-edsc/879) points out that ValueHandle has become an unnecessary level of abstraction since MLIR switch from `Value *` to `Value` everywhere.
This revision removes this level of indirection.
Added:
Modified:
mlir/docs/Dialects/Linalg.md
mlir/docs/EDSC.md
mlir/include/mlir/Dialect/Affine/EDSC/Builders.h
mlir/include/mlir/Dialect/Linalg/EDSC/Builders.h
mlir/include/mlir/Dialect/Linalg/EDSC/FoldedIntrinsics.h
mlir/include/mlir/Dialect/LoopOps/EDSC/Builders.h
mlir/include/mlir/Dialect/StandardOps/EDSC/Builders.h
mlir/include/mlir/Dialect/StandardOps/EDSC/Intrinsics.h
mlir/include/mlir/Dialect/Vector/EDSC/Intrinsics.h
mlir/include/mlir/EDSC/Builders.h
mlir/include/mlir/EDSC/Intrinsics.h
mlir/lib/Conversion/VectorToLoops/ConvertVectorToLoops.cpp
mlir/lib/Dialect/Affine/EDSC/Builders.cpp
mlir/lib/Dialect/GPU/Transforms/MemoryPromotion.cpp
mlir/lib/Dialect/Linalg/EDSC/Builders.cpp
mlir/lib/Dialect/Linalg/Transforms/Fusion.cpp
mlir/lib/Dialect/Linalg/Transforms/LinalgToLoops.cpp
mlir/lib/Dialect/Linalg/Transforms/LinalgTransforms.cpp
mlir/lib/Dialect/Linalg/Transforms/Promotion.cpp
mlir/lib/Dialect/Linalg/Transforms/Tiling.cpp
mlir/lib/Dialect/LoopOps/EDSC/Builders.cpp
mlir/lib/Dialect/StandardOps/EDSC/Builders.cpp
mlir/lib/Dialect/StandardOps/EDSC/Intrinsics.cpp
mlir/lib/EDSC/Builders.cpp
mlir/test/EDSC/builder-api-test.cpp
mlir/test/mlir-linalg-ods-gen/test-linalg-ods-gen.tc
mlir/tools/mlir-linalg-ods-gen/mlir-linalg-ods-gen.cpp
Removed:
################################################################################
diff --git a/mlir/docs/Dialects/Linalg.md b/mlir/docs/Dialects/Linalg.md
index 30afdafb582d..4673a7330330 100644
--- a/mlir/docs/Dialects/Linalg.md
+++ b/mlir/docs/Dialects/Linalg.md
@@ -531,9 +531,9 @@ llvm::Optional<SmallVector<AffineMap, 8>> batchmatmul::referenceIndexingMaps() {
void batchmatmul::regionBuilder(ArrayRef<BlockArgument> args) {
using namespace edsc;
using namespace intrinsics;
- ValueHandle _0(args[0]), _1(args[1]), _2(args[2]);
- ValueHandle _4 = std_mulf(_0, _1);
- ValueHandle _5 = std_addf(_2, _4);
+ Value _0(args[0]), _1(args[1]), _2(args[2]);
+ Value _4 = std_mulf(_0, _1);
+ Value _5 = std_addf(_2, _4);
(linalg_yield(ValueRange{ _5 }));
}
```
diff --git a/mlir/docs/EDSC.md b/mlir/docs/EDSC.md
index c52643bc5b28..b31a3583a7fb 100644
--- a/mlir/docs/EDSC.md
+++ b/mlir/docs/EDSC.md
@@ -13,30 +13,17 @@ case, in C++.
supporting a simple declarative API with globally accessible builders. These
declarative builders are available within the lifetime of a `ScopedContext`.
-## ValueHandle and IndexHandle
-
-`mlir::edsc::ValueHandle` and `mlir::edsc::IndexHandle` provide typed
-abstractions around an `mlir::Value`. These abstractions are "delayed", in the
-sense that they allow separating declaration from definition. They may capture
-IR snippets, as they are built, for programmatic manipulation. Intuitive
-operators are provided to allow concise and idiomatic expressions.
-
-```c++
-ValueHandle zero = std_constant_index(0);
-IndexHandle i, j, k;
-```
-
## Intrinsics
-`mlir::edsc::ValueBuilder` is a generic wrapper for the `mlir::Builder::create`
-method that operates on `ValueHandle` objects and return a single ValueHandle.
-For instructions that return no values or that return multiple values, the
-`mlir::edsc::InstructionBuilder` can be used. Named intrinsics are provided as
+`mlir::ValueBuilder` is a generic wrapper for the `mlir::OpBuilder::create`
+method that operates on `Value` objects and return a single Value. For
+instructions that return no values or that return multiple values, the
+`mlir::edsc::OperationBuilder` can be used. Named intrinsics are provided as
syntactic sugar to further reduce boilerplate.
```c++
using load = ValueBuilder<LoadOp>;
-using store = InstructionBuilder<StoreOp>;
+using store = OperationBuilder<StoreOp>;
```
## LoopBuilder and AffineLoopNestBuilder
@@ -46,14 +33,11 @@ concise and structured loop nests.
```c++
ScopedContext scope(f.get());
- ValueHandle i(indexType),
- j(indexType),
- lb(f->getArgument(0)),
- ub(f->getArgument(1));
- ValueHandle f7(std_constant_float(llvm::APFloat(7.0f), f32Type)),
- f13(std_constant_float(llvm::APFloat(13.0f), f32Type)),
- i7(constant_int(7, 32)),
- i13(constant_int(13, 32));
+ Value i, j, lb(f->getArgument(0)), ub(f->getArgument(1));
+ Value f7(std_constant_float(llvm::APFloat(7.0f), f32Type)),
+ f13(std_constant_float(llvm::APFloat(13.0f), f32Type)),
+ i7(constant_int(7, 32)),
+ i13(constant_int(13, 32));
AffineLoopNestBuilder(&i, lb, ub, 3)([&]{
lb * index_type(3) + ub;
lb + index_type(3);
@@ -84,11 +68,10 @@ def AddOp : Op<"x.add">,
Arguments<(ins Tensor:$A, Tensor:$B)>,
Results<(outs Tensor: $C)> {
code referenceImplementation = [{
- auto ivs = makeIndexHandles(view_A.rank());
- auto pivs = makePIndexHandles(ivs);
+ SmallVector<Value, 4> ivs(view_A.rank());
IndexedValue A(arg_A), B(arg_B), C(arg_C);
- AffineLoopNestBuilder(pivs, view_A.getLbs(), view_A.getUbs(), view_A.getSteps())(
- [&]{
+ AffineLoopNestBuilder(
+ ivs, view_A.getLbs(), view_A.getUbs(), view_A.getSteps())([&]{
C(ivs) = A(ivs) + B(ivs)
});
}];
@@ -124,10 +107,4 @@ Similar APIs are provided to emit the lower-level `loop.for` op with
`LoopNestBuilder`. See the `builder-api-test.cpp` test for more usage examples.
Since the implementation of declarative builders is in C++, it is also available
-to program the IR with an embedded-DSL flavor directly integrated in MLIR. We
-make use of these properties in the tutorial.
-
-Spoiler: MLIR also provides Python bindings for these builders, and a
-full-fledged Python machine learning DSL with automatic
diff erentiation
-targeting MLIR was built as an early research collaboration.
-
+to program the IR with an embedded-DSL flavor directly integrated in MLIR.
diff --git a/mlir/include/mlir/Dialect/Affine/EDSC/Builders.h b/mlir/include/mlir/Dialect/Affine/EDSC/Builders.h
index 9c320ece2209..863915aa15bf 100644
--- a/mlir/include/mlir/Dialect/Affine/EDSC/Builders.h
+++ b/mlir/include/mlir/Dialect/Affine/EDSC/Builders.h
@@ -23,12 +23,10 @@ namespace mlir {
namespace edsc {
/// Constructs a new AffineForOp and captures the associated induction
-/// variable. A ValueHandle pointer is passed as the first argument and is the
+/// variable. A Value pointer is passed as the first argument and is the
/// *only* way to capture the loop induction variable.
-LoopBuilder makeAffineLoopBuilder(ValueHandle *iv,
- ArrayRef<ValueHandle> lbHandles,
- ArrayRef<ValueHandle> ubHandles,
- int64_t step);
+LoopBuilder makeAffineLoopBuilder(Value *iv, ArrayRef<Value> lbs,
+ ArrayRef<Value> ubs, int64_t step);
/// Explicit nested LoopBuilder. Offers a compressed multi-loop builder to avoid
/// explicitly writing all the loops in a nest. This simple functionality is
@@ -58,10 +56,10 @@ class AffineLoopNestBuilder {
/// This entry point accommodates the fact that AffineForOp implicitly uses
/// multiple `lbs` and `ubs` with one single `iv` and `step` to encode `max`
/// and and `min` constraints respectively.
- AffineLoopNestBuilder(ValueHandle *iv, ArrayRef<ValueHandle> lbs,
- ArrayRef<ValueHandle> ubs, int64_t step);
- AffineLoopNestBuilder(ArrayRef<ValueHandle *> ivs, ArrayRef<ValueHandle> lbs,
- ArrayRef<ValueHandle> ubs, ArrayRef<int64_t> steps);
+ AffineLoopNestBuilder(Value *iv, ArrayRef<Value> lbs, ArrayRef<Value> ubs,
+ int64_t step);
+ AffineLoopNestBuilder(MutableArrayRef<Value> ivs, ArrayRef<Value> lbs,
+ ArrayRef<Value> ubs, ArrayRef<int64_t> steps);
void operator()(function_ref<void(void)> fun = nullptr);
@@ -71,133 +69,134 @@ class AffineLoopNestBuilder {
namespace op {
-ValueHandle operator+(ValueHandle lhs, ValueHandle rhs);
-ValueHandle operator-(ValueHandle lhs, ValueHandle rhs);
-ValueHandle operator*(ValueHandle lhs, ValueHandle rhs);
-ValueHandle operator/(ValueHandle lhs, ValueHandle rhs);
-ValueHandle operator%(ValueHandle lhs, ValueHandle rhs);
-ValueHandle floorDiv(ValueHandle lhs, ValueHandle rhs);
-ValueHandle ceilDiv(ValueHandle lhs, ValueHandle rhs);
-
-ValueHandle operator!(ValueHandle value);
-ValueHandle operator&&(ValueHandle lhs, ValueHandle rhs);
-ValueHandle operator||(ValueHandle lhs, ValueHandle rhs);
-ValueHandle operator^(ValueHandle lhs, ValueHandle rhs);
-ValueHandle operator==(ValueHandle lhs, ValueHandle rhs);
-ValueHandle operator!=(ValueHandle lhs, ValueHandle rhs);
-ValueHandle operator<(ValueHandle lhs, ValueHandle rhs);
-ValueHandle operator<=(ValueHandle lhs, ValueHandle rhs);
-ValueHandle operator>(ValueHandle lhs, ValueHandle rhs);
-ValueHandle operator>=(ValueHandle lhs, ValueHandle rhs);
+Value operator+(Value lhs, Value rhs);
+Value operator-(Value lhs, Value rhs);
+Value operator*(Value lhs, Value rhs);
+Value operator/(Value lhs, Value rhs);
+Value operator%(Value lhs, Value rhs);
+Value floorDiv(Value lhs, Value rhs);
+Value ceilDiv(Value lhs, Value rhs);
+
+/// Logical operator overloadings.
+Value negate(Value value);
+Value operator&&(Value lhs, Value rhs);
+Value operator||(Value lhs, Value rhs);
+Value operator^(Value lhs, Value rhs);
+
+/// Comparison operator overloadings.
+Value eq(Value lhs, Value rhs);
+Value ne(Value lhs, Value rhs);
+Value operator<(Value lhs, Value rhs);
+Value operator<=(Value lhs, Value rhs);
+Value operator>(Value lhs, Value rhs);
+Value operator>=(Value lhs, Value rhs);
} // namespace op
/// Arithmetic operator overloadings.
template <typename Load, typename Store>
-ValueHandle TemplatedIndexedValue<Load, Store>::operator+(ValueHandle e) {
+Value TemplatedIndexedValue<Load, Store>::operator+(Value e) {
using op::operator+;
- return static_cast<ValueHandle>(*this) + e;
+ return static_cast<Value>(*this) + e;
}
template <typename Load, typename Store>
-ValueHandle TemplatedIndexedValue<Load, Store>::operator-(ValueHandle e) {
+Value TemplatedIndexedValue<Load, Store>::operator-(Value e) {
using op::operator-;
- return static_cast<ValueHandle>(*this) - e;
+ return static_cast<Value>(*this) - e;
}
template <typename Load, typename Store>
-ValueHandle TemplatedIndexedValue<Load, Store>::operator*(ValueHandle e) {
+Value TemplatedIndexedValue<Load, Store>::operator*(Value e) {
using op::operator*;
- return static_cast<ValueHandle>(*this) * e;
+ return static_cast<Value>(*this) * e;
}
template <typename Load, typename Store>
-ValueHandle TemplatedIndexedValue<Load, Store>::operator/(ValueHandle e) {
+Value TemplatedIndexedValue<Load, Store>::operator/(Value e) {
using op::operator/;
- return static_cast<ValueHandle>(*this) / e;
+ return static_cast<Value>(*this) / e;
}
template <typename Load, typename Store>
-ValueHandle TemplatedIndexedValue<Load, Store>::operator%(ValueHandle e) {
+Value TemplatedIndexedValue<Load, Store>::operator%(Value e) {
using op::operator%;
- return static_cast<ValueHandle>(*this) % e;
+ return static_cast<Value>(*this) % e;
}
template <typename Load, typename Store>
-ValueHandle TemplatedIndexedValue<Load, Store>::operator^(ValueHandle e) {
+Value TemplatedIndexedValue<Load, Store>::operator^(Value e) {
using op::operator^;
- return static_cast<ValueHandle>(*this) ^ e;
+ return static_cast<Value>(*this) ^ e;
}
/// Assignment-arithmetic operator overloadings.
template <typename Load, typename Store>
-OperationHandle TemplatedIndexedValue<Load, Store>::operator+=(ValueHandle e) {
+OperationHandle TemplatedIndexedValue<Load, Store>::operator+=(Value e) {
using op::operator+;
return Store(*this + e, getBase(), {indices.begin(), indices.end()});
}
template <typename Load, typename Store>
-OperationHandle TemplatedIndexedValue<Load, Store>::operator-=(ValueHandle e) {
+OperationHandle TemplatedIndexedValue<Load, Store>::operator-=(Value e) {
using op::operator-;
return Store(*this - e, getBase(), {indices.begin(), indices.end()});
}
template <typename Load, typename Store>
-OperationHandle TemplatedIndexedValue<Load, Store>::operator*=(ValueHandle e) {
+OperationHandle TemplatedIndexedValue<Load, Store>::operator*=(Value e) {
using op::operator*;
return Store(*this * e, getBase(), {indices.begin(), indices.end()});
}
template <typename Load, typename Store>
-OperationHandle TemplatedIndexedValue<Load, Store>::operator/=(ValueHandle e) {
+OperationHandle TemplatedIndexedValue<Load, Store>::operator/=(Value e) {
using op::operator/;
return Store(*this / e, getBase(), {indices.begin(), indices.end()});
}
template <typename Load, typename Store>
-OperationHandle TemplatedIndexedValue<Load, Store>::operator%=(ValueHandle e) {
+OperationHandle TemplatedIndexedValue<Load, Store>::operator%=(Value e) {
using op::operator%;
return Store(*this % e, getBase(), {indices.begin(), indices.end()});
}
template <typename Load, typename Store>
-OperationHandle TemplatedIndexedValue<Load, Store>::operator^=(ValueHandle e) {
+OperationHandle TemplatedIndexedValue<Load, Store>::operator^=(Value e) {
using op::operator^;
return Store(*this ^ e, getBase(), {indices.begin(), indices.end()});
}
/// Logical operator overloadings.
template <typename Load, typename Store>
-ValueHandle TemplatedIndexedValue<Load, Store>::operator&&(ValueHandle e) {
+Value TemplatedIndexedValue<Load, Store>::operator&&(Value e) {
using op::operator&&;
- return static_cast<ValueHandle>(*this) && e;
+ return static_cast<Value>(*this) && e;
}
template <typename Load, typename Store>
-ValueHandle TemplatedIndexedValue<Load, Store>::operator||(ValueHandle e) {
+Value TemplatedIndexedValue<Load, Store>::operator||(Value e) {
using op::operator||;
- return static_cast<ValueHandle>(*this) || e;
+ return static_cast<Value>(*this) || e;
}
/// Comparison operator overloadings.
template <typename Load, typename Store>
-ValueHandle TemplatedIndexedValue<Load, Store>::operator==(ValueHandle e) {
- using op::operator==;
- return static_cast<ValueHandle>(*this) == e;
+Value TemplatedIndexedValue<Load, Store>::eq(Value e) {
+ return eq(value, e);
}
template <typename Load, typename Store>
-ValueHandle TemplatedIndexedValue<Load, Store>::operator!=(ValueHandle e) {
- using op::operator!=;
- return static_cast<ValueHandle>(*this) != e;
+Value TemplatedIndexedValue<Load, Store>::ne(Value e) {
+ return ne(value, e);
}
template <typename Load, typename Store>
-ValueHandle TemplatedIndexedValue<Load, Store>::operator<(ValueHandle e) {
+Value TemplatedIndexedValue<Load, Store>::operator<(Value e) {
using op::operator<;
- return static_cast<ValueHandle>(*this) < e;
+ return static_cast<Value>(*this) < e;
}
template <typename Load, typename Store>
-ValueHandle TemplatedIndexedValue<Load, Store>::operator<=(ValueHandle e) {
+Value TemplatedIndexedValue<Load, Store>::operator<=(Value e) {
using op::operator<=;
- return static_cast<ValueHandle>(*this) <= e;
+ return static_cast<Value>(*this) <= e;
}
template <typename Load, typename Store>
-ValueHandle TemplatedIndexedValue<Load, Store>::operator>(ValueHandle e) {
+Value TemplatedIndexedValue<Load, Store>::operator>(Value e) {
using op::operator>;
- return static_cast<ValueHandle>(*this) > e;
+ return static_cast<Value>(*this) > e;
}
template <typename Load, typename Store>
-ValueHandle TemplatedIndexedValue<Load, Store>::operator>=(ValueHandle e) {
+Value TemplatedIndexedValue<Load, Store>::operator>=(Value e) {
using op::operator>=;
- return static_cast<ValueHandle>(*this) >= e;
+ return static_cast<Value>(*this) >= e;
}
} // namespace edsc
diff --git a/mlir/include/mlir/Dialect/Linalg/EDSC/Builders.h b/mlir/include/mlir/Dialect/Linalg/EDSC/Builders.h
index 66cd8c002ff2..1608a1ad4ab1 100644
--- a/mlir/include/mlir/Dialect/Linalg/EDSC/Builders.h
+++ b/mlir/include/mlir/Dialect/Linalg/EDSC/Builders.h
@@ -42,11 +42,10 @@ class ParallelLoopNestBuilder;
class LoopRangeBuilder : public NestedBuilder {
public:
/// Constructs a new loop.for and captures the associated induction
- /// variable. A ValueHandle pointer is passed as the first argument and is the
+ /// variable. A Value pointer is passed as the first argument and is the
/// *only* way to capture the loop induction variable.
- LoopRangeBuilder(ValueHandle *iv, ValueHandle range);
- LoopRangeBuilder(ValueHandle *iv, Value range);
- LoopRangeBuilder(ValueHandle *iv, SubViewOp::Range range);
+ LoopRangeBuilder(Value *iv, Value range);
+ LoopRangeBuilder(Value *iv, SubViewOp::Range range);
LoopRangeBuilder(const LoopRangeBuilder &) = delete;
LoopRangeBuilder(LoopRangeBuilder &&) = default;
@@ -57,7 +56,7 @@ class LoopRangeBuilder : public NestedBuilder {
/// The only purpose of this operator is to serve as a sequence point so that
/// the evaluation of `fun` (which build IR snippets in a scoped fashion) is
/// scoped within a LoopRangeBuilder.
- ValueHandle operator()(std::function<void(void)> fun = nullptr);
+ Value operator()(std::function<void(void)> fun = nullptr);
};
/// Helper class to sugar building loop.for loop nests from ranges.
@@ -65,13 +64,10 @@ class LoopRangeBuilder : public NestedBuilder {
/// directly. In the current implementation it produces loop.for operations.
class LoopNestRangeBuilder {
public:
- LoopNestRangeBuilder(ArrayRef<edsc::ValueHandle *> ivs,
- ArrayRef<edsc::ValueHandle> ranges);
- LoopNestRangeBuilder(ArrayRef<edsc::ValueHandle *> ivs,
- ArrayRef<Value> ranges);
- LoopNestRangeBuilder(ArrayRef<edsc::ValueHandle *> ivs,
+ LoopNestRangeBuilder(MutableArrayRef<Value> ivs, ArrayRef<Value> ranges);
+ LoopNestRangeBuilder(MutableArrayRef<Value> ivs,
ArrayRef<SubViewOp::Range> ranges);
- edsc::ValueHandle operator()(std::function<void(void)> fun = nullptr);
+ Value operator()(std::function<void(void)> fun = nullptr);
private:
SmallVector<LoopRangeBuilder, 4> loops;
@@ -81,7 +77,7 @@ class LoopNestRangeBuilder {
/// ranges.
template <typename LoopTy> class GenericLoopNestRangeBuilder {
public:
- GenericLoopNestRangeBuilder(ArrayRef<edsc::ValueHandle *> ivs,
+ GenericLoopNestRangeBuilder(MutableArrayRef<Value> ivs,
ArrayRef<Value> ranges);
void operator()(std::function<void(void)> fun = nullptr) { (*builder)(fun); }
@@ -124,7 +120,6 @@ Operation *makeGenericLinalgOp(
namespace ops {
using edsc::StructuredIndexed;
-using edsc::ValueHandle;
//===----------------------------------------------------------------------===//
// EDSC builders for linalg generic operations.
@@ -160,7 +155,7 @@ void macRegionBuilder(ArrayRef<BlockArgument> args);
/// with in-place semantics and parallelism.
/// Unary pointwise operation (with broadcast) entry point.
-using UnaryPointwiseOpBuilder = function_ref<Value(ValueHandle)>;
+using UnaryPointwiseOpBuilder = function_ref<Value(Value)>;
Operation *linalg_generic_pointwise(UnaryPointwiseOpBuilder unaryOp,
StructuredIndexed I, StructuredIndexed O);
@@ -171,7 +166,7 @@ Operation *linalg_generic_pointwise_tanh(StructuredIndexed I,
StructuredIndexed O);
/// Binary pointwise operation (with broadcast) entry point.
-using BinaryPointwiseOpBuilder = function_ref<Value(ValueHandle, ValueHandle)>;
+using BinaryPointwiseOpBuilder = function_ref<Value(Value, Value)>;
Operation *linalg_generic_pointwise(BinaryPointwiseOpBuilder binaryOp,
StructuredIndexed I1, StructuredIndexed I2,
StructuredIndexed O);
@@ -202,7 +197,7 @@ using MatmulRegionBuilder = function_ref<void(ArrayRef<BlockArgument> args)>;
/// | C(m, n) += A(m, k) * B(k, n)
/// ```
Operation *
-linalg_generic_matmul(ValueHandle vA, ValueHandle vB, ValueHandle vC,
+linalg_generic_matmul(Value vA, Value vB, Value vC,
MatmulRegionBuilder regionBuilder = macRegionBuilder);
/// Build a linalg.generic, under the current ScopedContext, at the current
@@ -214,7 +209,7 @@ linalg_generic_matmul(ValueHandle vA, ValueHandle vB, ValueHandle vC,
/// ```
/// and returns the tensor `C`.
Operation *
-linalg_generic_matmul(ValueHandle vA, ValueHandle vB, RankedTensorType tC,
+linalg_generic_matmul(Value vA, Value vB, RankedTensorType tC,
MatmulRegionBuilder regionBuilder = mulRegionBuilder);
/// Build a linalg.generic, under the current ScopedContext, at the current
@@ -226,8 +221,7 @@ linalg_generic_matmul(ValueHandle vA, ValueHandle vB, RankedTensorType tC,
/// ```
/// and returns the tensor `D`.
Operation *
-linalg_generic_matmul(ValueHandle vA, ValueHandle vB, ValueHandle vC,
- RankedTensorType tD,
+linalg_generic_matmul(Value vA, Value vB, Value vC, RankedTensorType tD,
MatmulRegionBuilder regionBuilder = macRegionBuilder);
template <typename Container>
@@ -260,8 +254,8 @@ linalg_generic_matmul(Container values,
/// For now `...` must be empty (i.e. only 2-D convolutions are supported).
///
// TODO(ntv) Extend convolution rank with some template magic.
-Operation *linalg_generic_conv_nhwc(ValueHandle vI, ValueHandle vW,
- ValueHandle vO, ArrayRef<int> strides = {},
+Operation *linalg_generic_conv_nhwc(Value vI, Value vW, Value vO,
+ ArrayRef<int> strides = {},
ArrayRef<int> dilations = {});
template <typename Container>
@@ -295,8 +289,7 @@ Operation *linalg_generic_conv_nhwc(Container values,
/// For now `...` must be empty (i.e. only 2-D convolutions are supported).
///
// TODO(ntv) Extend convolution rank with some template magic.
-Operation *linalg_generic_dilated_conv_nhwc(ValueHandle vI, ValueHandle vW,
- ValueHandle vO,
+Operation *linalg_generic_dilated_conv_nhwc(Value vI, Value vW, Value vO,
int depth_multiplier = 1,
ArrayRef<int> strides = {},
ArrayRef<int> dilations = {});
diff --git a/mlir/include/mlir/Dialect/Linalg/EDSC/FoldedIntrinsics.h b/mlir/include/mlir/Dialect/Linalg/EDSC/FoldedIntrinsics.h
index 89cde8ff3513..2c506a87dc5e 100644
--- a/mlir/include/mlir/Dialect/Linalg/EDSC/FoldedIntrinsics.h
+++ b/mlir/include/mlir/Dialect/Linalg/EDSC/FoldedIntrinsics.h
@@ -15,16 +15,52 @@
namespace mlir {
namespace edsc {
+namespace intrinsics {
-template <typename Op, typename... Args>
-ValueHandle ValueHandle::create(OperationFolder *folder, Args... args) {
- return folder ? ValueHandle(folder->create<Op>(ScopedContext::getBuilder(),
- ScopedContext::getLocation(),
- args...))
- : ValueHandle(ScopedContext::getBuilder().create<Op>(
- ScopedContext::getLocation(), args...));
-}
+template <typename Op>
+struct FoldedValueBuilder {
+ // Builder-based
+ template <typename... Args>
+ FoldedValueBuilder(OperationFolder *folder, Args... args) {
+ value = folder ? folder->create<Op>(ScopedContext::getBuilder(),
+ ScopedContext::getLocation(), args...)
+ : ScopedContext::getBuilder().create<Op>(
+ ScopedContext::getLocation(), args...);
+ }
+ operator Value() { return value; }
+ Value value;
+};
+
+using folded_std_constant_index = FoldedValueBuilder<ConstantIndexOp>;
+using folded_std_constant_float = FoldedValueBuilder<ConstantFloatOp>;
+using folded_std_constant_int = FoldedValueBuilder<ConstantIntOp>;
+using folded_std_constant = FoldedValueBuilder<ConstantOp>;
+using folded_std_dim = FoldedValueBuilder<DimOp>;
+using folded_std_muli = FoldedValueBuilder<MulIOp>;
+using folded_std_addi = FoldedValueBuilder<AddIOp>;
+using folded_std_addf = FoldedValueBuilder<AddFOp>;
+using folded_std_alloc = FoldedValueBuilder<AllocOp>;
+using folded_std_constant = FoldedValueBuilder<ConstantOp>;
+using folded_std_constant_float = FoldedValueBuilder<ConstantFloatOp>;
+using folded_std_constant_index = FoldedValueBuilder<ConstantIndexOp>;
+using folded_std_constant_int = FoldedValueBuilder<ConstantIntOp>;
+using folded_std_dim = FoldedValueBuilder<DimOp>;
+using folded_std_extract_element = FoldedValueBuilder<ExtractElementOp>;
+using folded_std_index_cast = FoldedValueBuilder<IndexCastOp>;
+using folded_std_muli = FoldedValueBuilder<MulIOp>;
+using folded_std_mulf = FoldedValueBuilder<MulFOp>;
+using folded_std_memref_cast = FoldedValueBuilder<MemRefCastOp>;
+using folded_std_select = FoldedValueBuilder<SelectOp>;
+using folded_std_load = FoldedValueBuilder<LoadOp>;
+using folded_std_subi = FoldedValueBuilder<SubIOp>;
+using folded_std_sub_view = FoldedValueBuilder<SubViewOp>;
+using folded_std_tanh = FoldedValueBuilder<TanhOp>;
+using folded_std_tensor_load = FoldedValueBuilder<TensorLoadOp>;
+using folded_std_view = FoldedValueBuilder<ViewOp>;
+using folded_std_zero_extendi = FoldedValueBuilder<ZeroExtendIOp>;
+using folded_std_sign_extendi = FoldedValueBuilder<SignExtendIOp>;
+} // namespace intrinsics
} // namespace edsc
} // namespace mlir
diff --git a/mlir/include/mlir/Dialect/LoopOps/EDSC/Builders.h b/mlir/include/mlir/Dialect/LoopOps/EDSC/Builders.h
index f4b30aa54879..3d884869d293 100644
--- a/mlir/include/mlir/Dialect/LoopOps/EDSC/Builders.h
+++ b/mlir/include/mlir/Dialect/LoopOps/EDSC/Builders.h
@@ -23,27 +23,30 @@ namespace mlir {
namespace edsc {
/// Constructs a new loop::ParallelOp and captures the associated induction
-/// variables. An array of ValueHandle pointers is passed as the first
+/// variables. An array of Value pointers is passed as the first
/// argument and is the *only* way to capture loop induction variables.
-LoopBuilder makeParallelLoopBuilder(ArrayRef<ValueHandle *> ivs,
- ArrayRef<ValueHandle> lbHandles,
- ArrayRef<ValueHandle> ubHandles,
- ArrayRef<ValueHandle> steps);
+LoopBuilder makeParallelLoopBuilder(MutableArrayRef<Value> ivs,
+ ArrayRef<Value> lbs, ArrayRef<Value> ubs,
+ ArrayRef<Value> steps);
/// Constructs a new loop::ForOp and captures the associated induction
-/// variable. A ValueHandle pointer is passed as the first argument and is the
+/// variable. A Value pointer is passed as the first argument and is the
/// *only* way to capture the loop induction variable.
-LoopBuilder makeLoopBuilder(ValueHandle *iv, ValueHandle lbHandle,
- ValueHandle ubHandle, ValueHandle stepHandle,
- ArrayRef<ValueHandle *> iter_args_handles = {},
- ValueRange iter_args_init_values = {});
+LoopBuilder makeLoopBuilder(Value *iv, Value lb, Value ub, Value step,
+ MutableArrayRef<Value> iterArgsHandles,
+ ValueRange iterArgsInitValues);
+LoopBuilder makeLoopBuilder(Value *iv, Value lb, Value ub, Value step,
+ MutableArrayRef<Value> iterArgsHandles,
+ ValueRange iterArgsInitValues);
+inline LoopBuilder makeLoopBuilder(Value *iv, Value lb, Value ub, Value step) {
+ return makeLoopBuilder(iv, lb, ub, step, MutableArrayRef<Value>{}, {});
+}
/// Helper class to sugar building loop.parallel loop nests from lower/upper
/// bounds and step sizes.
class ParallelLoopNestBuilder {
public:
- ParallelLoopNestBuilder(ArrayRef<ValueHandle *> ivs,
- ArrayRef<ValueHandle> lbs, ArrayRef<ValueHandle> ubs,
- ArrayRef<ValueHandle> steps);
+ ParallelLoopNestBuilder(MutableArrayRef<Value> ivs, ArrayRef<Value> lbs,
+ ArrayRef<Value> ubs, ArrayRef<Value> steps);
void operator()(function_ref<void(void)> fun = nullptr);
@@ -56,12 +59,12 @@ class ParallelLoopNestBuilder {
/// loop.for.
class LoopNestBuilder {
public:
- LoopNestBuilder(ValueHandle *iv, ValueHandle lb, ValueHandle ub,
- ValueHandle step,
- ArrayRef<ValueHandle *> iter_args_handles = {},
- ValueRange iter_args_init_values = {});
- LoopNestBuilder(ArrayRef<ValueHandle *> ivs, ArrayRef<ValueHandle> lbs,
- ArrayRef<ValueHandle> ubs, ArrayRef<ValueHandle> steps);
+ LoopNestBuilder(Value *iv, Value lb, Value ub, Value step);
+ LoopNestBuilder(Value *iv, Value lb, Value ub, Value step,
+ MutableArrayRef<Value> iterArgsHandles,
+ ValueRange iterArgsInitValues);
+ LoopNestBuilder(MutableArrayRef<Value> ivs, ArrayRef<Value> lbs,
+ ArrayRef<Value> ubs, ArrayRef<Value> steps);
Operation::result_range operator()(std::function<void(void)> fun = nullptr);
private:
diff --git a/mlir/include/mlir/Dialect/StandardOps/EDSC/Builders.h b/mlir/include/mlir/Dialect/StandardOps/EDSC/Builders.h
index 53d9f49af4a5..8df7021d6627 100644
--- a/mlir/include/mlir/Dialect/StandardOps/EDSC/Builders.h
+++ b/mlir/include/mlir/Dialect/StandardOps/EDSC/Builders.h
@@ -20,27 +20,27 @@ namespace edsc {
class BoundsCapture {
public:
unsigned rank() const { return lbs.size(); }
- ValueHandle lb(unsigned idx) { return lbs[idx]; }
- ValueHandle ub(unsigned idx) { return ubs[idx]; }
+ Value lb(unsigned idx) { return lbs[idx]; }
+ Value ub(unsigned idx) { return ubs[idx]; }
int64_t step(unsigned idx) { return steps[idx]; }
- std::tuple<ValueHandle, ValueHandle, int64_t> range(unsigned idx) {
+ std::tuple<Value, Value, int64_t> range(unsigned idx) {
return std::make_tuple(lbs[idx], ubs[idx], steps[idx]);
}
void swapRanges(unsigned i, unsigned j) {
if (i == j)
return;
- lbs[i].swap(lbs[j]);
- ubs[i].swap(ubs[j]);
+ std::swap(lbs[i], lbs[j]);
+ std::swap(ubs[i], ubs[j]);
std::swap(steps[i], steps[j]);
}
- ArrayRef<ValueHandle> getLbs() { return lbs; }
- ArrayRef<ValueHandle> getUbs() { return ubs; }
+ ArrayRef<Value> getLbs() { return lbs; }
+ ArrayRef<Value> getUbs() { return ubs; }
ArrayRef<int64_t> getSteps() { return steps; }
protected:
- SmallVector<ValueHandle, 8> lbs;
- SmallVector<ValueHandle, 8> ubs;
+ SmallVector<Value, 8> lbs;
+ SmallVector<Value, 8> ubs;
SmallVector<int64_t, 8> steps;
};
@@ -58,7 +58,7 @@ class MemRefBoundsCapture : public BoundsCapture {
unsigned fastestVarying() const { return rank() - 1; }
private:
- ValueHandle base;
+ Value base;
};
/// A VectorBoundsCapture represents the information required to step through a
@@ -72,7 +72,7 @@ class VectorBoundsCapture : public BoundsCapture {
VectorBoundsCapture &operator=(const VectorBoundsCapture &) = default;
private:
- ValueHandle base;
+ Value base;
};
} // namespace edsc
diff --git a/mlir/include/mlir/Dialect/StandardOps/EDSC/Intrinsics.h b/mlir/include/mlir/Dialect/StandardOps/EDSC/Intrinsics.h
index 50dc0a0050f0..ca1a19609490 100644
--- a/mlir/include/mlir/Dialect/StandardOps/EDSC/Intrinsics.h
+++ b/mlir/include/mlir/Dialect/StandardOps/EDSC/Intrinsics.h
@@ -14,40 +14,6 @@
namespace mlir {
namespace edsc {
namespace intrinsics {
-namespace folded {
-/// Helper variadic abstraction to allow extending to any MLIR op without
-/// boilerplate or Tablegen.
-/// Arguably a builder is not a ValueHandle but in practice it is only used as
-/// an alias to a notional ValueHandle<Op>.
-/// Implementing it as a subclass allows it to compose all the way to Value.
-/// Without subclassing, implicit conversion to Value would fail when composing
-/// in patterns such as: `select(a, b, select(c, d, e))`.
-template <typename Op>
-struct ValueBuilder : public ValueHandle {
- /// Folder-based
- template <typename... Args>
- ValueBuilder(OperationFolder *folder, Args... args)
- : ValueHandle(ValueHandle::create<Op>(folder, detail::unpack(args)...)) {}
- ValueBuilder(OperationFolder *folder, ArrayRef<ValueHandle> vs)
- : ValueBuilder(ValueBuilder::create<Op>(folder, detail::unpack(vs))) {}
- template <typename... Args>
- ValueBuilder(OperationFolder *folder, ArrayRef<ValueHandle> vs, Args... args)
- : ValueHandle(ValueHandle::create<Op>(folder, detail::unpack(vs),
- detail::unpack(args)...)) {}
- template <typename T, typename... Args>
- ValueBuilder(OperationFolder *folder, T t, ArrayRef<ValueHandle> vs,
- Args... args)
- : ValueHandle(ValueHandle::create<Op>(folder, detail::unpack(t),
- detail::unpack(vs),
- detail::unpack(args)...)) {}
- template <typename T1, typename T2, typename... Args>
- ValueBuilder(OperationFolder *folder, T1 t1, T2 t2, ArrayRef<ValueHandle> vs,
- Args... args)
- : ValueHandle(ValueHandle::create<Op>(
- folder, detail::unpack(t1), detail::unpack(t2), detail::unpack(vs),
- detail::unpack(args)...)) {}
-};
-} // namespace folded
using std_addf = ValueBuilder<AddFOp>;
using std_alloc = ValueBuilder<AllocOp>;
@@ -80,7 +46,7 @@ using std_sign_extendi = ValueBuilder<SignExtendIOp>;
///
/// Prerequisites:
/// All Handles have already captured previously constructed IR objects.
-OperationHandle std_br(BlockHandle bh, ArrayRef<ValueHandle> operands);
+OperationHandle std_br(BlockHandle bh, ArrayRef<Value> operands);
/// Creates a new mlir::Block* and branches to it from the current block.
/// Argument types are specified by `operands`.
@@ -95,8 +61,9 @@ OperationHandle std_br(BlockHandle bh, ArrayRef<ValueHandle> operands);
/// All `operands` have already captured an mlir::Value
/// captures.size() == operands.size()
/// captures and operands are pairwise of the same type.
-OperationHandle std_br(BlockHandle *bh, ArrayRef<ValueHandle *> captures,
- ArrayRef<ValueHandle> operands);
+OperationHandle std_br(BlockHandle *bh, ArrayRef<Type> types,
+ MutableArrayRef<Value> captures,
+ ArrayRef<Value> operands);
/// Branches into the mlir::Block* captured by BlockHandle `trueBranch` with
/// `trueOperands` if `cond` evaluates to `true` (resp. `falseBranch` and
@@ -104,10 +71,10 @@ OperationHandle std_br(BlockHandle *bh, ArrayRef<ValueHandle *> captures,
///
/// Prerequisites:
/// All Handles have captured previously constructed IR objects.
-OperationHandle std_cond_br(ValueHandle cond, BlockHandle trueBranch,
- ArrayRef<ValueHandle> trueOperands,
+OperationHandle std_cond_br(Value cond, BlockHandle trueBranch,
+ ArrayRef<Value> trueOperands,
BlockHandle falseBranch,
- ArrayRef<ValueHandle> falseOperands);
+ ArrayRef<Value> falseOperands);
/// Eagerly creates new mlir::Block* with argument types specified by
/// `trueOperands`/`falseOperands`.
@@ -125,45 +92,17 @@ OperationHandle std_cond_br(ValueHandle cond, BlockHandle trueBranch,
/// `falseCaptures`.size() == `falseOperands`.size()
/// `trueCaptures` and `trueOperands` are pairwise of the same type
/// `falseCaptures` and `falseOperands` are pairwise of the same type.
-OperationHandle std_cond_br(ValueHandle cond, BlockHandle *trueBranch,
- ArrayRef<ValueHandle *> trueCaptures,
- ArrayRef<ValueHandle> trueOperands,
- BlockHandle *falseBranch,
- ArrayRef<ValueHandle *> falseCaptures,
- ArrayRef<ValueHandle> falseOperands);
+OperationHandle std_cond_br(Value cond, BlockHandle *trueBranch,
+ ArrayRef<Type> trueTypes,
+ MutableArrayRef<Value> trueCaptures,
+ ArrayRef<Value> trueOperands,
+ BlockHandle *falseBranch, ArrayRef<Type> falseTypes,
+ MutableArrayRef<Value> falseCaptures,
+ ArrayRef<Value> falseOperands);
/// Provide an index notation around sdt_load and std_store.
using StdIndexedValue =
TemplatedIndexedValue<intrinsics::std_load, intrinsics::std_store>;
-
-using folded_std_constant_index = folded::ValueBuilder<ConstantIndexOp>;
-using folded_std_constant_float = folded::ValueBuilder<ConstantFloatOp>;
-using folded_std_constant_int = folded::ValueBuilder<ConstantIntOp>;
-using folded_std_constant = folded::ValueBuilder<ConstantOp>;
-using folded_std_dim = folded::ValueBuilder<DimOp>;
-using folded_std_muli = folded::ValueBuilder<MulIOp>;
-using folded_std_addi = folded::ValueBuilder<AddIOp>;
-using folded_std_addf = folded::ValueBuilder<AddFOp>;
-using folded_std_alloc = folded::ValueBuilder<AllocOp>;
-using folded_std_constant = folded::ValueBuilder<ConstantOp>;
-using folded_std_constant_float = folded::ValueBuilder<ConstantFloatOp>;
-using folded_std_constant_index = folded::ValueBuilder<ConstantIndexOp>;
-using folded_std_constant_int = folded::ValueBuilder<ConstantIntOp>;
-using folded_std_dim = folded::ValueBuilder<DimOp>;
-using folded_std_extract_element = folded::ValueBuilder<ExtractElementOp>;
-using folded_std_index_cast = folded::ValueBuilder<IndexCastOp>;
-using folded_std_muli = folded::ValueBuilder<MulIOp>;
-using folded_std_mulf = folded::ValueBuilder<MulFOp>;
-using folded_std_memref_cast = folded::ValueBuilder<MemRefCastOp>;
-using folded_std_select = folded::ValueBuilder<SelectOp>;
-using folded_std_load = folded::ValueBuilder<LoadOp>;
-using folded_std_subi = folded::ValueBuilder<SubIOp>;
-using folded_std_sub_view = folded::ValueBuilder<SubViewOp>;
-using folded_std_tanh = folded::ValueBuilder<TanhOp>;
-using folded_std_tensor_load = folded::ValueBuilder<TensorLoadOp>;
-using folded_std_view = folded::ValueBuilder<ViewOp>;
-using folded_std_zero_extendi = folded::ValueBuilder<ZeroExtendIOp>;
-using folded_std_sign_extendi = folded::ValueBuilder<SignExtendIOp>;
} // namespace intrinsics
} // namespace edsc
} // namespace mlir
diff --git a/mlir/include/mlir/Dialect/Vector/EDSC/Intrinsics.h b/mlir/include/mlir/Dialect/Vector/EDSC/Intrinsics.h
index 79ab479c6133..87e552c561e2 100644
--- a/mlir/include/mlir/Dialect/Vector/EDSC/Intrinsics.h
+++ b/mlir/include/mlir/Dialect/Vector/EDSC/Intrinsics.h
@@ -18,6 +18,7 @@ using vector_broadcast = ValueBuilder<vector::BroadcastOp>;
using vector_contract = ValueBuilder<vector::ContractionOp>;
using vector_matmul = ValueBuilder<vector::MatmulOp>;
using vector_print = OperationBuilder<vector::PrintOp>;
+using vector_type_cast = ValueBuilder<vector::TypeCastOp>;
} // namespace intrinsics
} // namespace edsc
diff --git a/mlir/include/mlir/EDSC/Builders.h b/mlir/include/mlir/EDSC/Builders.h
index 9c5a8e72c66e..0ef894930ed8 100644
--- a/mlir/include/mlir/EDSC/Builders.h
+++ b/mlir/include/mlir/EDSC/Builders.h
@@ -24,9 +24,7 @@ class OperationFolder;
namespace edsc {
class BlockHandle;
-class CapturableHandle;
class NestedBuilder;
-class ValueHandle;
/// Helper class to transparently handle builder insertion points by RAII.
/// As its name indicates, a ScopedContext is means to be used locally in a
@@ -70,10 +68,23 @@ class ScopedContext {
/// Defensively keeps track of the current NestedBuilder to ensure proper
/// scoping usage.
NestedBuilder *nestedBuilder;
+};
+
+template <typename Op>
+struct ValueBuilder {
+ // Builder-based
+ template <typename... Args>
+ ValueBuilder(Args... args) {
+ Operation *op = ScopedContext::getBuilder()
+ .create<Op>(ScopedContext::getLocation(), args...)
+ .getOperation();
+ if (op->getNumResults() != 1)
+ llvm_unreachable("unsupported operation, use OperationBuilder instead");
+ value = op->getResult(0);
+ }
- // TODO: Implement scoping of ValueHandles. To do this we need a proper data
- // structure to hold ValueHandle objects. We can emulate one but there should
- // already be something available in LLVM for this purpose.
+ operator Value() { return value; }
+ Value value;
};
/// A NestedBuilder is a scoping abstraction to create an idiomatic syntax
@@ -82,8 +93,7 @@ class ScopedContext {
/// exists between object construction and method invocation on said object (in
/// our case, the call to `operator()`).
/// This ordering allows implementing an abstraction that decouples definition
-/// from declaration (in a PL sense) on placeholders of type ValueHandle and
-/// BlockHandle.
+/// from declaration (in a PL sense) on placeholders.
class NestedBuilder {
protected:
NestedBuilder() = default;
@@ -158,19 +168,17 @@ class LoopBuilder : public NestedBuilder {
private:
LoopBuilder() = default;
- friend LoopBuilder makeAffineLoopBuilder(ValueHandle *iv,
- ArrayRef<ValueHandle> lbHandles,
- ArrayRef<ValueHandle> ubHandles,
+ friend LoopBuilder makeAffineLoopBuilder(Value *iv, ArrayRef<Value> lbHandles,
+ ArrayRef<Value> ubHandles,
int64_t step);
- friend LoopBuilder makeParallelLoopBuilder(ArrayRef<ValueHandle *> ivs,
- ArrayRef<ValueHandle> lbHandles,
- ArrayRef<ValueHandle> ubHandles,
- ArrayRef<ValueHandle> steps);
- friend LoopBuilder makeLoopBuilder(ValueHandle *iv, ValueHandle lbHandle,
- ValueHandle ubHandle,
- ValueHandle stepHandle,
- ArrayRef<ValueHandle *> iter_args_handles,
- ValueRange iter_args_init_values);
+ friend LoopBuilder makeParallelLoopBuilder(MutableArrayRef<Value> ivs,
+ ArrayRef<Value> lbHandles,
+ ArrayRef<Value> ubHandles,
+ ArrayRef<Value> steps);
+ friend LoopBuilder makeLoopBuilder(Value *iv, Value lbHandle, Value ubHandle,
+ Value stepHandle,
+ MutableArrayRef<Value> iterArgsHandles,
+ ValueRange iterArgsInitValues);
Operation *op;
};
@@ -194,9 +202,11 @@ class BlockBuilder : public NestedBuilder {
/// Enters the new mlir::Block* and sets the insertion point to its end.
///
/// Prerequisites:
- /// The ValueHandle `args` are typed delayed ValueHandles; i.e. they are
+ /// The Value `args` are typed delayed Values; i.e. they are
/// not yet bound to mlir::Value.
- BlockBuilder(BlockHandle *bh, ArrayRef<ValueHandle *> args);
+ BlockBuilder(BlockHandle *bh) : BlockBuilder(bh, {}, {}) {}
+ BlockBuilder(BlockHandle *bh, ArrayRef<Type> types,
+ MutableArrayRef<Value> args);
/// Constructs a new mlir::Block with argument types derived from `args` and
/// appends it as the last block in the region.
@@ -204,9 +214,10 @@ class BlockBuilder : public NestedBuilder {
/// Enters the new mlir::Block* and sets the insertion point to its end.
///
/// Prerequisites:
- /// The ValueHandle `args` are typed delayed ValueHandles; i.e. they are
+ /// The Value `args` are typed delayed Values; i.e. they are
/// not yet bound to mlir::Value.
- BlockBuilder(BlockHandle *bh, Region ®ion, ArrayRef<ValueHandle *> args);
+ BlockBuilder(BlockHandle *bh, Region ®ion, ArrayRef<Type> types,
+ MutableArrayRef<Value> args);
/// The only purpose of this operator is to serve as a sequence point so that
/// the evaluation of `fun` (which build IR snippets in a scoped fashion) is
@@ -218,120 +229,18 @@ class BlockBuilder : public NestedBuilder {
BlockBuilder &operator=(BlockBuilder &other) = delete;
};
-/// Base class for ValueHandle, OperationHandle and BlockHandle.
+/// Base class for Value, OperationHandle and BlockHandle.
/// Not meant to be used outside of these classes.
class CapturableHandle {
protected:
CapturableHandle() = default;
};
-/// ValueHandle implements a (potentially "delayed") typed Value abstraction.
-/// ValueHandle should be captured by pointer but otherwise passed by Value
-/// everywhere.
-/// A ValueHandle can have 3 states:
-/// 1. null state (empty type and empty value), in which case it does not hold
-/// a value and must never hold a Value (now or in the future). This is
-/// used for MLIR operations with zero returns as well as the result of
-/// calling a NestedBuilder::operator(). In both cases the objective is to
-/// have an object that can be inserted in an ArrayRef<ValueHandle> to
-/// implement nesting;
-/// 2. delayed state (empty value), in which case it represents an eagerly
-/// typed "delayed" value that can be hold a Value in the future;
-/// 3. constructed state,in which case it holds a Value.
-///
-/// A ValueHandle is meant to capture a single Value and should be used for
-/// operations that have a single result. For convenience of use, we also
-/// include AffineForOp in this category although it does not return a value.
-/// In the case of AffineForOp, the captured Value is the loop induction
-/// variable.
-class ValueHandle : public CapturableHandle {
-public:
- /// A ValueHandle in a null state can never be captured;
- static ValueHandle null() { return ValueHandle(); }
-
- /// A ValueHandle that is constructed from a Type represents a typed "delayed"
- /// Value. A delayed Value can only capture Values of the specified type.
- /// Such a delayed value represents the declaration (in the PL sense) of a
- /// placeholder for an mlir::Value that will be constructed and captured at
- /// some later point in the program.
- explicit ValueHandle(Type t) : t(t), v(nullptr) {}
-
- /// A ValueHandle that is constructed from an mlir::Value is an "eager"
- /// Value. An eager Value represents both the declaration and the definition
- /// (in the PL sense) of a placeholder for an mlir::Value that has already
- /// been constructed in the past and that is captured "now" in the program.
- explicit ValueHandle(Value v) : t(v.getType()), v(v) {}
-
- /// ValueHandle is a value type, use the default copy constructor.
- ValueHandle(const ValueHandle &other) = default;
-
- /// ValueHandle is a value type, the assignment operator typechecks before
- /// assigning.
- ValueHandle &operator=(const ValueHandle &other);
-
- /// Provide a swap operator.
- void swap(ValueHandle &other) {
- if (this == &other)
- return;
- std::swap(t, other.t);
- std::swap(v, other.v);
- }
-
- /// Implicit conversion useful for automatic conversion to Container<Value>.
- operator Value() const { return getValue(); }
- operator Type() const { return getType(); }
- operator bool() const { return hasValue(); }
-
- /// Generic mlir::Op create. This is the key to being extensible to the whole
- /// of MLIR without duplicating the type system or the op definitions.
- template <typename Op, typename... Args>
- static ValueHandle create(Args... args);
-
- /// Generic mlir::Op create. This is the key to being extensible to the whole
- /// of MLIR without duplicating the type system or the op definitions.
- /// When non-null, the optional pointer `folder` is used to call into the
- /// `createAndFold` builder method. If `folder` is null, the regular `create`
- /// method is called.
- template <typename Op, typename... Args>
- static ValueHandle create(OperationFolder *folder, Args... args);
-
- /// Generic create for a named operation producing a single value.
- static ValueHandle create(StringRef name, ArrayRef<ValueHandle> operands,
- ArrayRef<Type> resultTypes,
- ArrayRef<NamedAttribute> attributes = {});
-
- bool hasValue() const { return v != nullptr; }
- Value getValue() const {
- assert(hasValue() && "Unexpected null value;");
- return v;
- }
- bool hasType() const { return t != Type(); }
- Type getType() const { return t; }
-
- Operation *getOperation() const {
- if (!v)
- return nullptr;
- return v.getDefiningOp();
- }
-
- // Return a vector of fresh ValueHandles that have not captured.
- static SmallVector<ValueHandle, 8> makeIndexHandles(unsigned count) {
- auto indexType = IndexType::get(ScopedContext::getContext());
- return SmallVector<ValueHandle, 8>(count, ValueHandle(indexType));
- }
-
-protected:
- ValueHandle() : t(), v(nullptr) {}
-
- Type t;
- Value v;
-};
-
-/// An OperationHandle can be used in lieu of ValueHandle to capture the
+/// An OperationHandle can be used in lieu of Value to capture the
/// operation in cases when one does not care about, or cannot extract, a
/// unique Value from the operation.
/// This can be used for capturing zero result operations as well as
-/// multi-result operations that are not supported by ValueHandle.
+/// multi-result operations that are not supported by Value.
/// We do not distinguish further between zero and multi-result operations at
/// this time.
struct OperationHandle : public CapturableHandle {
@@ -349,7 +258,7 @@ struct OperationHandle : public CapturableHandle {
static Op createOp(Args... args);
/// Generic create for a named operation.
- static OperationHandle create(StringRef name, ArrayRef<ValueHandle> operands,
+ static OperationHandle create(StringRef name, ArrayRef<Value> operands,
ArrayRef<Type> resultTypes,
ArrayRef<NamedAttribute> attributes = {});
@@ -360,23 +269,6 @@ struct OperationHandle : public CapturableHandle {
Operation *op;
};
-/// Simple wrapper to build a generic operation without successor blocks.
-template <typename HandleType>
-struct CustomOperation {
- CustomOperation(StringRef name) : name(name) {
- static_assert(std::is_same<HandleType, ValueHandle>() ||
- std::is_same<HandleType, OperationHandle>(),
- "Only CustomOperation<ValueHandle> or "
- "CustomOperation<OperationHandle> can be constructed.");
- }
- HandleType operator()(ArrayRef<ValueHandle> operands = {},
- ArrayRef<Type> resultTypes = {},
- ArrayRef<NamedAttribute> attributes = {}) {
- return HandleType::create(name, operands, resultTypes, attributes);
- }
- std::string name;
-};
-
/// A BlockHandle represents a (potentially "delayed") Block abstraction.
/// This extra abstraction is necessary because an mlir::Block is not an
/// mlir::Value.
@@ -427,32 +319,45 @@ class BlockHandle : public CapturableHandle {
/// C(buffer_value_or_tensor_type);
/// makeGenericLinalgOp({A({m, n}), B({k, n})}, {C({m, n})}, ... );
/// ```
-struct StructuredIndexed : public ValueHandle {
- StructuredIndexed(Type type) : ValueHandle(type) {}
- StructuredIndexed(Value value) : ValueHandle(value) {}
- StructuredIndexed(ValueHandle valueHandle) : ValueHandle(valueHandle) {}
+struct StructuredIndexed {
+ StructuredIndexed(Value v) : value(v) {}
+ StructuredIndexed(Type t) : type(t) {}
StructuredIndexed operator()(ArrayRef<AffineExpr> indexings) {
- return this->hasValue() ? StructuredIndexed(this->getValue(), indexings)
- : StructuredIndexed(this->getType(), indexings);
+ return value ? StructuredIndexed(value, indexings)
+ : StructuredIndexed(type, indexings);
}
- StructuredIndexed(Type t, ArrayRef<AffineExpr> indexings)
- : ValueHandle(t), exprs(indexings.begin(), indexings.end()) {
- assert(t.isa<RankedTensorType>() && "RankedTensor expected");
- }
StructuredIndexed(Value v, ArrayRef<AffineExpr> indexings)
- : ValueHandle(v), exprs(indexings.begin(), indexings.end()) {
+ : value(v), exprs(indexings.begin(), indexings.end()) {
assert((v.getType().isa<MemRefType>() ||
v.getType().isa<RankedTensorType>() ||
v.getType().isa<VectorType>()) &&
"MemRef, RankedTensor or Vector expected");
}
- StructuredIndexed(ValueHandle vh, ArrayRef<AffineExpr> indexings)
- : ValueHandle(vh), exprs(indexings.begin(), indexings.end()) {}
+ StructuredIndexed(Type t, ArrayRef<AffineExpr> indexings)
+ : type(t), exprs(indexings.begin(), indexings.end()) {
+ assert((t.isa<MemRefType>() || t.isa<RankedTensorType>() ||
+ t.isa<VectorType>()) &&
+ "MemRef, RankedTensor or Vector expected");
+ }
- ArrayRef<AffineExpr> getExprs() { return exprs; }
+ bool hasValue() const { return value; }
+ Value getValue() const {
+ assert(value && "StructuredIndexed Value not set.");
+ return value;
+ }
+ Type getType() const {
+ assert((value || type) && "StructuredIndexed Value and Type not set.");
+ return value ? value.getType() : type;
+ }
+ ArrayRef<AffineExpr> getExprs() const { return exprs; }
+ operator Value() const { return getValue(); }
+ operator Type() const { return getType(); }
private:
+ // Only one of Value or type may be set.
+ Type type;
+ Value value;
SmallVector<AffineExpr, 4> exprs;
};
@@ -472,179 +377,139 @@ Op OperationHandle::createOp(Args... args) {
.getOperation());
}
-template <typename Op, typename... Args>
-ValueHandle ValueHandle::create(Args... args) {
- Operation *op = ScopedContext::getBuilder()
- .create<Op>(ScopedContext::getLocation(), args...)
- .getOperation();
- if (op->getNumResults() == 1)
- return ValueHandle(op->getResult(0));
- llvm_unreachable("unsupported operation, use an OperationHandle instead");
-}
-
-/// Entry point to build multiple ValueHandle from a `Container` of Value or
-/// Type.
-template <typename Container>
-inline SmallVector<ValueHandle, 8> makeValueHandles(Container values) {
- SmallVector<ValueHandle, 8> res;
- res.reserve(values.size());
- for (auto v : values)
- res.push_back(ValueHandle(v));
- return res;
-}
-
/// A TemplatedIndexedValue brings an index notation over the template Load and
/// Store parameters. Assigning to an IndexedValue emits an actual `Store`
-/// operation, while converting an IndexedValue to a ValueHandle emits an actual
+/// operation, while converting an IndexedValue to a Value emits an actual
/// `Load` operation.
template <typename Load, typename Store>
class TemplatedIndexedValue {
public:
- explicit TemplatedIndexedValue(Type t) : base(t) {}
- explicit TemplatedIndexedValue(Value v)
- : TemplatedIndexedValue(ValueHandle(v)) {}
- explicit TemplatedIndexedValue(ValueHandle v) : base(v) {}
+ explicit TemplatedIndexedValue(Value v) : value(v) {}
TemplatedIndexedValue(const TemplatedIndexedValue &rhs) = default;
TemplatedIndexedValue operator()() { return *this; }
/// Returns a new `TemplatedIndexedValue`.
- TemplatedIndexedValue operator()(ValueHandle index) {
- TemplatedIndexedValue res(base);
+ TemplatedIndexedValue operator()(Value index) {
+ TemplatedIndexedValue res(value);
res.indices.push_back(index);
return res;
}
template <typename... Args>
- TemplatedIndexedValue operator()(ValueHandle index, Args... indices) {
- return TemplatedIndexedValue(base, index).append(indices...);
+ TemplatedIndexedValue operator()(Value index, Args... indices) {
+ return TemplatedIndexedValue(value, index).append(indices...);
}
- TemplatedIndexedValue operator()(ArrayRef<ValueHandle> indices) {
- return TemplatedIndexedValue(base, indices);
+ TemplatedIndexedValue operator()(ArrayRef<Value> indices) {
+ return TemplatedIndexedValue(value, indices);
}
/// Emits a `store`.
OperationHandle operator=(const TemplatedIndexedValue &rhs) {
- ValueHandle rrhs(rhs);
- return Store(rrhs, getBase(), {indices.begin(), indices.end()});
- }
- OperationHandle operator=(ValueHandle rhs) {
- return Store(rhs, getBase(), {indices.begin(), indices.end()});
- }
-
- /// Emits a `load` when converting to a ValueHandle.
- operator ValueHandle() const {
- return Load(getBase(), {indices.begin(), indices.end()});
+ return Store(rhs, value, indices);
}
+ OperationHandle operator=(Value rhs) { return Store(rhs, value, indices); }
/// Emits a `load` when converting to a Value.
- Value operator*(void)const {
- return Load(getBase(), {indices.begin(), indices.end()}).getValue();
- }
+ operator Value() const { return Load(value, indices); }
- ValueHandle getBase() const { return base; }
+ Value getBase() const { return value; }
/// Arithmetic operator overloadings.
- ValueHandle operator+(ValueHandle e);
- ValueHandle operator-(ValueHandle e);
- ValueHandle operator*(ValueHandle e);
- ValueHandle operator/(ValueHandle e);
- ValueHandle operator%(ValueHandle e);
- ValueHandle operator^(ValueHandle e);
- ValueHandle operator+(TemplatedIndexedValue e) {
- return *this + static_cast<ValueHandle>(e);
+ Value operator+(Value e);
+ Value operator-(Value e);
+ Value operator*(Value e);
+ Value operator/(Value e);
+ Value operator%(Value e);
+ Value operator^(Value e);
+ Value operator+(TemplatedIndexedValue e) {
+ return *this + static_cast<Value>(e);
}
- ValueHandle operator-(TemplatedIndexedValue e) {
- return *this - static_cast<ValueHandle>(e);
+ Value operator-(TemplatedIndexedValue e) {
+ return *this - static_cast<Value>(e);
}
- ValueHandle operator*(TemplatedIndexedValue e) {
- return *this * static_cast<ValueHandle>(e);
+ Value operator*(TemplatedIndexedValue e) {
+ return *this * static_cast<Value>(e);
}
- ValueHandle operator/(TemplatedIndexedValue e) {
- return *this / static_cast<ValueHandle>(e);
+ Value operator/(TemplatedIndexedValue e) {
+ return *this / static_cast<Value>(e);
}
- ValueHandle operator%(TemplatedIndexedValue e) {
- return *this % static_cast<ValueHandle>(e);
+ Value operator%(TemplatedIndexedValue e) {
+ return *this % static_cast<Value>(e);
}
- ValueHandle operator^(TemplatedIndexedValue e) {
- return *this ^ static_cast<ValueHandle>(e);
+ Value operator^(TemplatedIndexedValue e) {
+ return *this ^ static_cast<Value>(e);
}
/// Assignment-arithmetic operator overloadings.
- OperationHandle operator+=(ValueHandle e);
- OperationHandle operator-=(ValueHandle e);
- OperationHandle operator*=(ValueHandle e);
- OperationHandle operator/=(ValueHandle e);
- OperationHandle operator%=(ValueHandle e);
- OperationHandle operator^=(ValueHandle e);
+ OperationHandle operator+=(Value e);
+ OperationHandle operator-=(Value e);
+ OperationHandle operator*=(Value e);
+ OperationHandle operator/=(Value e);
+ OperationHandle operator%=(Value e);
+ OperationHandle operator^=(Value e);
OperationHandle operator+=(TemplatedIndexedValue e) {
- return this->operator+=(static_cast<ValueHandle>(e));
+ return this->operator+=(static_cast<Value>(e));
}
OperationHandle operator-=(TemplatedIndexedValue e) {
- return this->operator-=(static_cast<ValueHandle>(e));
+ return this->operator-=(static_cast<Value>(e));
}
OperationHandle operator*=(TemplatedIndexedValue e) {
- return this->operator*=(static_cast<ValueHandle>(e));
+ return this->operator*=(static_cast<Value>(e));
}
OperationHandle operator/=(TemplatedIndexedValue e) {
- return this->operator/=(static_cast<ValueHandle>(e));
+ return this->operator/=(static_cast<Value>(e));
}
OperationHandle operator%=(TemplatedIndexedValue e) {
- return this->operator%=(static_cast<ValueHandle>(e));
+ return this->operator%=(static_cast<Value>(e));
}
OperationHandle operator^=(TemplatedIndexedValue e) {
- return this->operator^=(static_cast<ValueHandle>(e));
+ return this->operator^=(static_cast<Value>(e));
}
/// Logical operator overloadings.
- ValueHandle operator&&(ValueHandle e);
- ValueHandle operator||(ValueHandle e);
- ValueHandle operator&&(TemplatedIndexedValue e) {
- return *this && static_cast<ValueHandle>(e);
+ Value operator&&(Value e);
+ Value operator||(Value e);
+ Value operator&&(TemplatedIndexedValue e) {
+ return *this && static_cast<Value>(e);
}
- ValueHandle operator||(TemplatedIndexedValue e) {
- return *this || static_cast<ValueHandle>(e);
+ Value operator||(TemplatedIndexedValue e) {
+ return *this || static_cast<Value>(e);
}
/// Comparison operator overloadings.
- ValueHandle operator==(ValueHandle e);
- ValueHandle operator!=(ValueHandle e);
- ValueHandle operator<(ValueHandle e);
- ValueHandle operator<=(ValueHandle e);
- ValueHandle operator>(ValueHandle e);
- ValueHandle operator>=(ValueHandle e);
- ValueHandle operator==(TemplatedIndexedValue e) {
- return *this == static_cast<ValueHandle>(e);
- }
- ValueHandle operator!=(TemplatedIndexedValue e) {
- return *this != static_cast<ValueHandle>(e);
- }
- ValueHandle operator<(TemplatedIndexedValue e) {
- return *this < static_cast<ValueHandle>(e);
+ Value eq(Value e);
+ Value ne(Value e);
+ Value operator<(Value e);
+ Value operator<=(Value e);
+ Value operator>(Value e);
+ Value operator>=(Value e);
+ Value operator<(TemplatedIndexedValue e) {
+ return *this < static_cast<Value>(e);
}
- ValueHandle operator<=(TemplatedIndexedValue e) {
- return *this <= static_cast<ValueHandle>(e);
+ Value operator<=(TemplatedIndexedValue e) {
+ return *this <= static_cast<Value>(e);
}
- ValueHandle operator>(TemplatedIndexedValue e) {
- return *this > static_cast<ValueHandle>(e);
+ Value operator>(TemplatedIndexedValue e) {
+ return *this > static_cast<Value>(e);
}
- ValueHandle operator>=(TemplatedIndexedValue e) {
- return *this >= static_cast<ValueHandle>(e);
+ Value operator>=(TemplatedIndexedValue e) {
+ return *this >= static_cast<Value>(e);
}
private:
- TemplatedIndexedValue(ValueHandle base, ArrayRef<ValueHandle> indices)
- : base(base), indices(indices.begin(), indices.end()) {}
+ TemplatedIndexedValue(Value value, ArrayRef<Value> indices)
+ : value(value), indices(indices.begin(), indices.end()) {}
TemplatedIndexedValue &append() { return *this; }
template <typename T, typename... Args>
TemplatedIndexedValue &append(T index, Args... indices) {
- this->indices.push_back(static_cast<ValueHandle>(index));
+ this->indices.push_back(static_cast<Value>(index));
append(indices...);
return *this;
}
- ValueHandle base;
- SmallVector<ValueHandle, 8> indices;
+ Value value;
+ SmallVector<Value, 8> indices;
};
} // namespace edsc
diff --git a/mlir/include/mlir/EDSC/Intrinsics.h b/mlir/include/mlir/EDSC/Intrinsics.h
index 3e82eddc39c1..14fa16ae0602 100644
--- a/mlir/include/mlir/EDSC/Intrinsics.h
+++ b/mlir/include/mlir/EDSC/Intrinsics.h
@@ -25,99 +25,27 @@ class Type;
namespace edsc {
-/// Entry point to build multiple ValueHandle* from a mutable list `ivs`.
-inline SmallVector<ValueHandle *, 8>
-makeHandlePointers(MutableArrayRef<ValueHandle> ivs) {
- SmallVector<ValueHandle *, 8> pivs;
- pivs.reserve(ivs.size());
- for (auto &iv : ivs)
- pivs.push_back(&iv);
- return pivs;
-}
-
/// Provides a set of first class intrinsics.
/// In the future, most of intrinsics related to Operation that don't contain
/// other operations should be Tablegen'd.
namespace intrinsics {
-namespace detail {
-/// Helper structure to be used with ValueBuilder / OperationBuilder.
-/// It serves the purpose of removing boilerplate specialization for the sole
-/// purpose of implicitly converting ArrayRef<ValueHandle> -> ArrayRef<Value>.
-class ValueHandleArray {
-public:
- ValueHandleArray(ArrayRef<ValueHandle> vals) {
- values.append(vals.begin(), vals.end());
- }
- operator ArrayRef<Value>() { return values; }
-
-private:
- ValueHandleArray() = default;
- SmallVector<Value, 8> values;
-};
-
-template <typename T>
-inline T unpack(T value) {
- return value;
-}
-
-inline detail::ValueHandleArray unpack(ArrayRef<ValueHandle> values) {
- return detail::ValueHandleArray(values);
-}
-
-} // namespace detail
-
-/// Helper variadic abstraction to allow extending to any MLIR op without
-/// boilerplate or Tablegen.
-/// Arguably a builder is not a ValueHandle but in practice it is only used as
-/// an alias to a notional ValueHandle<Op>.
-/// Implementing it as a subclass allows it to compose all the way to Value.
-/// Without subclassing, implicit conversion to Value would fail when composing
-/// in patterns such as: `select(a, b, select(c, d, e))`.
-template <typename Op>
-struct ValueBuilder : public ValueHandle {
- // Builder-based
- template <typename... Args>
- ValueBuilder(Args... args)
- : ValueHandle(ValueHandle::create<Op>(detail::unpack(args)...)) {}
- ValueBuilder(ArrayRef<ValueHandle> vs)
- : ValueBuilder(ValueBuilder::create<Op>(detail::unpack(vs))) {}
- template <typename... Args>
- ValueBuilder(ArrayRef<ValueHandle> vs, Args... args)
- : ValueHandle(ValueHandle::create<Op>(detail::unpack(vs),
- detail::unpack(args)...)) {}
- template <typename T, typename... Args>
- ValueBuilder(T t, ArrayRef<ValueHandle> vs, Args... args)
- : ValueHandle(ValueHandle::create<Op>(
- detail::unpack(t), detail::unpack(vs), detail::unpack(args)...)) {}
- template <typename T1, typename T2, typename... Args>
- ValueBuilder(T1 t1, T2 t2, ArrayRef<ValueHandle> vs, Args... args)
- : ValueHandle(ValueHandle::create<Op>(
- detail::unpack(t1), detail::unpack(t2), detail::unpack(vs),
- detail::unpack(args)...)) {}
-
- ValueBuilder() : ValueHandle(ValueHandle::create<Op>()) {}
-};
template <typename Op>
struct OperationBuilder : public OperationHandle {
template <typename... Args>
OperationBuilder(Args... args)
- : OperationHandle(OperationHandle::create<Op>(detail::unpack(args)...)) {}
- OperationBuilder(ArrayRef<ValueHandle> vs)
- : OperationHandle(OperationHandle::create<Op>(detail::unpack(vs))) {}
+ : OperationHandle(OperationHandle::create<Op>(args...)) {}
+ OperationBuilder(ArrayRef<Value> vs)
+ : OperationHandle(OperationHandle::create<Op>(vs)) {}
template <typename... Args>
- OperationBuilder(ArrayRef<ValueHandle> vs, Args... args)
- : OperationHandle(OperationHandle::create<Op>(detail::unpack(vs),
- detail::unpack(args)...)) {}
+ OperationBuilder(ArrayRef<Value> vs, Args... args)
+ : OperationHandle(OperationHandle::create<Op>(vs, args...)) {}
template <typename T, typename... Args>
- OperationBuilder(T t, ArrayRef<ValueHandle> vs, Args... args)
- : OperationHandle(OperationHandle::create<Op>(
- detail::unpack(t), detail::unpack(vs), detail::unpack(args)...)) {}
+ OperationBuilder(T t, ArrayRef<Value> vs, Args... args)
+ : OperationHandle(OperationHandle::create<Op>(t, vs, args...)) {}
template <typename T1, typename T2, typename... Args>
- OperationBuilder(T1 t1, T2 t2, ArrayRef<ValueHandle> vs, Args... args)
- : OperationHandle(OperationHandle::create<Op>(
- detail::unpack(t1), detail::unpack(t2), detail::unpack(vs),
- detail::unpack(args)...)) {}
+ OperationBuilder(T1 t1, T2 t2, ArrayRef<Value> vs, Args... args)
+ : OperationHandle(OperationHandle::create<Op>(t1, t2, vs, args...)) {}
OperationBuilder() : OperationHandle(OperationHandle::create<Op>()) {}
};
diff --git a/mlir/lib/Conversion/VectorToLoops/ConvertVectorToLoops.cpp b/mlir/lib/Conversion/VectorToLoops/ConvertVectorToLoops.cpp
index b73d94562edc..99676f1335f6 100644
--- a/mlir/lib/Conversion/VectorToLoops/ConvertVectorToLoops.cpp
+++ b/mlir/lib/Conversion/VectorToLoops/ConvertVectorToLoops.cpp
@@ -16,6 +16,7 @@
#include "mlir/Dialect/Affine/EDSC/Intrinsics.h"
#include "mlir/Dialect/LoopOps/EDSC/Builders.h"
#include "mlir/Dialect/StandardOps/EDSC/Intrinsics.h"
+#include "mlir/Dialect/Vector/EDSC/Intrinsics.h"
#include "mlir/Dialect/Vector/VectorOps.h"
#include "mlir/IR/AffineExpr.h"
#include "mlir/IR/AffineMap.h"
@@ -38,9 +39,7 @@ using vector::TransferWriteOp;
/// `pivs` and `vectorBoundsCapture` are swapped so that the invocation of
/// LoopNestBuilder captures it in the innermost loop.
template <typename TransferOpTy>
-static void coalesceCopy(TransferOpTy transfer,
- SmallVectorImpl<ValueHandle *> *pivs,
- VectorBoundsCapture *vectorBoundsCapture) {
+static int computeCoalescedIndex(TransferOpTy transfer) {
// rank of the remote memory access, coalescing behavior occurs on the
// innermost memory dimension.
auto remoteRank = transfer.getMemRefType().getRank();
@@ -62,24 +61,19 @@ static void coalesceCopy(TransferOpTy transfer,
coalescedIdx = en.index();
}
}
- if (coalescedIdx >= 0) {
- std::swap(pivs->back(), (*pivs)[coalescedIdx]);
- vectorBoundsCapture->swapRanges(pivs->size() - 1, coalescedIdx);
- }
+ return coalescedIdx;
}
/// Emits remote memory accesses that are clipped to the boundaries of the
/// MemRef.
template <typename TransferOpTy>
-static SmallVector<ValueHandle, 8> clip(TransferOpTy transfer,
- MemRefBoundsCapture &bounds,
- ArrayRef<ValueHandle> ivs) {
+static SmallVector<Value, 8>
+clip(TransferOpTy transfer, MemRefBoundsCapture &bounds, ArrayRef<Value> ivs) {
using namespace mlir::edsc;
- ValueHandle zero(std_constant_index(0)), one(std_constant_index(1));
- SmallVector<ValueHandle, 8> memRefAccess(transfer.indices());
- auto clippedScalarAccessExprs =
- ValueHandle::makeIndexHandles(memRefAccess.size());
+ Value zero(std_constant_index(0)), one(std_constant_index(1));
+ SmallVector<Value, 8> memRefAccess(transfer.indices());
+ SmallVector<Value, 8> clippedScalarAccessExprs(memRefAccess.size());
// Indices accessing to remote memory are clipped and their expressions are
// returned in clippedScalarAccessExprs.
for (unsigned memRefDim = 0; memRefDim < clippedScalarAccessExprs.size();
@@ -126,8 +120,6 @@ static SmallVector<ValueHandle, 8> clip(TransferOpTy transfer,
namespace {
-using vector_type_cast = edsc::intrinsics::ValueBuilder<vector::TypeCastOp>;
-
/// Implements lowering of TransferReadOp and TransferWriteOp to a
/// proper abstraction for the hardware.
///
@@ -257,31 +249,36 @@ LogicalResult VectorTransferRewriter<TransferReadOp>::matchAndRewrite(
StdIndexedValue remote(transfer.memref());
MemRefBoundsCapture memRefBoundsCapture(transfer.memref());
VectorBoundsCapture vectorBoundsCapture(transfer.vector());
- auto ivs = ValueHandle::makeIndexHandles(vectorBoundsCapture.rank());
- SmallVector<ValueHandle *, 8> pivs =
- makeHandlePointers(MutableArrayRef<ValueHandle>(ivs));
- coalesceCopy(transfer, &pivs, &vectorBoundsCapture);
+ int coalescedIdx = computeCoalescedIndex(transfer);
+ // Swap the vectorBoundsCapture which will reorder loop bounds.
+ if (coalescedIdx >= 0)
+ vectorBoundsCapture.swapRanges(vectorBoundsCapture.rank() - 1,
+ coalescedIdx);
auto lbs = vectorBoundsCapture.getLbs();
auto ubs = vectorBoundsCapture.getUbs();
- SmallVector<ValueHandle, 8> steps;
+ SmallVector<Value, 8> steps;
steps.reserve(vectorBoundsCapture.getSteps().size());
for (auto step : vectorBoundsCapture.getSteps())
steps.push_back(std_constant_index(step));
// 2. Emit alloc-copy-load-dealloc.
- ValueHandle tmp = std_alloc(tmpMemRefType(transfer));
+ Value tmp = std_alloc(tmpMemRefType(transfer));
StdIndexedValue local(tmp);
- ValueHandle vec = vector_type_cast(tmp);
- LoopNestBuilder(pivs, lbs, ubs, steps)([&] {
+ Value vec = vector_type_cast(tmp);
+ SmallVector<Value, 8> ivs(lbs.size());
+ LoopNestBuilder(ivs, lbs, ubs, steps)([&] {
+ // Swap the ivs which will reorder memory accesses.
+ if (coalescedIdx >= 0)
+ std::swap(ivs.back(), ivs[coalescedIdx]);
// Computes clippedScalarAccessExprs in the loop nest scope (ivs exist).
local(ivs) = remote(clip(transfer, memRefBoundsCapture, ivs));
});
- ValueHandle vectorValue = std_load(vec);
+ Value vectorValue = std_load(vec);
(std_dealloc(tmp)); // vexing parse
// 3. Propagate.
- rewriter.replaceOp(op, vectorValue.getValue());
+ rewriter.replaceOp(op, vectorValue);
return success();
}
@@ -314,26 +311,31 @@ LogicalResult VectorTransferRewriter<TransferWriteOp>::matchAndRewrite(
ScopedContext scope(rewriter, transfer.getLoc());
StdIndexedValue remote(transfer.memref());
MemRefBoundsCapture memRefBoundsCapture(transfer.memref());
- ValueHandle vectorValue(transfer.vector());
+ Value vectorValue(transfer.vector());
VectorBoundsCapture vectorBoundsCapture(transfer.vector());
- auto ivs = ValueHandle::makeIndexHandles(vectorBoundsCapture.rank());
- SmallVector<ValueHandle *, 8> pivs =
- makeHandlePointers(MutableArrayRef<ValueHandle>(ivs));
- coalesceCopy(transfer, &pivs, &vectorBoundsCapture);
+ int coalescedIdx = computeCoalescedIndex(transfer);
+ // Swap the vectorBoundsCapture which will reorder loop bounds.
+ if (coalescedIdx >= 0)
+ vectorBoundsCapture.swapRanges(vectorBoundsCapture.rank() - 1,
+ coalescedIdx);
auto lbs = vectorBoundsCapture.getLbs();
auto ubs = vectorBoundsCapture.getUbs();
- SmallVector<ValueHandle, 8> steps;
+ SmallVector<Value, 8> steps;
steps.reserve(vectorBoundsCapture.getSteps().size());
for (auto step : vectorBoundsCapture.getSteps())
steps.push_back(std_constant_index(step));
// 2. Emit alloc-store-copy-dealloc.
- ValueHandle tmp = std_alloc(tmpMemRefType(transfer));
+ Value tmp = std_alloc(tmpMemRefType(transfer));
StdIndexedValue local(tmp);
- ValueHandle vec = vector_type_cast(tmp);
+ Value vec = vector_type_cast(tmp);
std_store(vectorValue, vec);
- LoopNestBuilder(pivs, lbs, ubs, steps)([&] {
+ SmallVector<Value, 8> ivs(lbs.size());
+ LoopNestBuilder(ivs, lbs, ubs, steps)([&] {
+ // Swap the ivs which will reorder memory accesses.
+ if (coalescedIdx >= 0)
+ std::swap(ivs.back(), ivs[coalescedIdx]);
// Computes clippedScalarAccessExprs in the loop nest scope (ivs exist).
remote(clip(transfer, memRefBoundsCapture, ivs)) = local(ivs);
});
diff --git a/mlir/lib/Dialect/Affine/EDSC/Builders.cpp b/mlir/lib/Dialect/Affine/EDSC/Builders.cpp
index 5d9034c9b6d5..2cecb0c12e18 100644
--- a/mlir/lib/Dialect/Affine/EDSC/Builders.cpp
+++ b/mlir/lib/Dialect/Affine/EDSC/Builders.cpp
@@ -14,65 +14,61 @@
using namespace mlir;
using namespace mlir::edsc;
-static Optional<ValueHandle> emitStaticFor(ArrayRef<ValueHandle> lbs,
- ArrayRef<ValueHandle> ubs,
- int64_t step) {
+static Optional<Value> emitStaticFor(ArrayRef<Value> lbs, ArrayRef<Value> ubs,
+ int64_t step) {
if (lbs.size() != 1 || ubs.size() != 1)
- return Optional<ValueHandle>();
+ return Optional<Value>();
- auto *lbDef = lbs.front().getValue().getDefiningOp();
- auto *ubDef = ubs.front().getValue().getDefiningOp();
+ auto *lbDef = lbs.front().getDefiningOp();
+ auto *ubDef = ubs.front().getDefiningOp();
if (!lbDef || !ubDef)
- return Optional<ValueHandle>();
+ return Optional<Value>();
auto lbConst = dyn_cast<ConstantIndexOp>(lbDef);
auto ubConst = dyn_cast<ConstantIndexOp>(ubDef);
if (!lbConst || !ubConst)
- return Optional<ValueHandle>();
-
- return ValueHandle(ScopedContext::getBuilder()
- .create<AffineForOp>(ScopedContext::getLocation(),
- lbConst.getValue(),
- ubConst.getValue(), step)
- .getInductionVar());
+ return Optional<Value>();
+ return ScopedContext::getBuilder()
+ .create<AffineForOp>(ScopedContext::getLocation(), lbConst.getValue(),
+ ubConst.getValue(), step)
+ .getInductionVar();
}
-LoopBuilder mlir::edsc::makeAffineLoopBuilder(ValueHandle *iv,
- ArrayRef<ValueHandle> lbHandles,
- ArrayRef<ValueHandle> ubHandles,
+LoopBuilder mlir::edsc::makeAffineLoopBuilder(Value *iv, ArrayRef<Value> lbs,
+ ArrayRef<Value> ubs,
int64_t step) {
mlir::edsc::LoopBuilder result;
- if (auto staticFor = emitStaticFor(lbHandles, ubHandles, step)) {
- *iv = staticFor.getValue();
+ if (auto staticForIv = emitStaticFor(lbs, ubs, step)) {
+ *iv = staticForIv.getValue();
} else {
- SmallVector<Value, 4> lbs(lbHandles.begin(), lbHandles.end());
- SmallVector<Value, 4> ubs(ubHandles.begin(), ubHandles.end());
auto b = ScopedContext::getBuilder();
- *iv = ValueHandle(
- b.create<AffineForOp>(ScopedContext::getLocation(), lbs,
- b.getMultiDimIdentityMap(lbs.size()), ubs,
- b.getMultiDimIdentityMap(ubs.size()), step)
- .getInductionVar());
+ *iv =
+ Value(b.create<AffineForOp>(ScopedContext::getLocation(), lbs,
+ b.getMultiDimIdentityMap(lbs.size()), ubs,
+ b.getMultiDimIdentityMap(ubs.size()), step)
+ .getInductionVar());
}
- auto *body = getForInductionVarOwner(iv->getValue()).getBody();
+
+ auto *body = getForInductionVarOwner(*iv).getBody();
result.enter(body, /*prev=*/1);
return result;
}
-mlir::edsc::AffineLoopNestBuilder::AffineLoopNestBuilder(
- ValueHandle *iv, ArrayRef<ValueHandle> lbs, ArrayRef<ValueHandle> ubs,
- int64_t step) {
+mlir::edsc::AffineLoopNestBuilder::AffineLoopNestBuilder(Value *iv,
+ ArrayRef<Value> lbs,
+ ArrayRef<Value> ubs,
+ int64_t step) {
loops.emplace_back(makeAffineLoopBuilder(iv, lbs, ubs, step));
}
mlir::edsc::AffineLoopNestBuilder::AffineLoopNestBuilder(
- ArrayRef<ValueHandle *> ivs, ArrayRef<ValueHandle> lbs,
- ArrayRef<ValueHandle> ubs, ArrayRef<int64_t> steps) {
+ MutableArrayRef<Value> ivs, ArrayRef<Value> lbs, ArrayRef<Value> ubs,
+ ArrayRef<int64_t> steps) {
assert(ivs.size() == lbs.size() && "Mismatch in number of arguments");
assert(ivs.size() == ubs.size() && "Mismatch in number of arguments");
assert(ivs.size() == steps.size() && "Mismatch in number of arguments");
for (auto it : llvm::zip(ivs, lbs, ubs, steps))
- loops.emplace_back(makeAffineLoopBuilder(std::get<0>(it), std::get<1>(it),
+ loops.emplace_back(makeAffineLoopBuilder(&std::get<0>(it), std::get<1>(it),
std::get<2>(it), std::get<3>(it)));
}
@@ -89,11 +85,6 @@ void mlir::edsc::AffineLoopNestBuilder::operator()(
(*lit)();
}
-template <typename Op>
-static ValueHandle createBinaryHandle(ValueHandle lhs, ValueHandle rhs) {
- return ValueHandle::create<Op>(lhs.getValue(), rhs.getValue());
-}
-
static std::pair<AffineExpr, Value>
categorizeValueByAffineType(MLIRContext *context, Value val, unsigned &numDims,
unsigned &numSymbols) {
@@ -111,115 +102,109 @@ categorizeValueByAffineType(MLIRContext *context, Value val, unsigned &numDims,
return std::make_pair(d, resultVal);
}
-static ValueHandle createBinaryIndexHandle(
- ValueHandle lhs, ValueHandle rhs,
+static Value createBinaryIndexHandle(
+ Value lhs, Value rhs,
function_ref<AffineExpr(AffineExpr, AffineExpr)> affCombiner) {
MLIRContext *context = ScopedContext::getContext();
unsigned numDims = 0, numSymbols = 0;
AffineExpr d0, d1;
Value v0, v1;
std::tie(d0, v0) =
- categorizeValueByAffineType(context, lhs.getValue(), numDims, numSymbols);
+ categorizeValueByAffineType(context, lhs, numDims, numSymbols);
std::tie(d1, v1) =
- categorizeValueByAffineType(context, rhs.getValue(), numDims, numSymbols);
+ categorizeValueByAffineType(context, rhs, numDims, numSymbols);
SmallVector<Value, 2> operands;
- if (v0) {
+ if (v0)
operands.push_back(v0);
- }
- if (v1) {
+ if (v1)
operands.push_back(v1);
- }
auto map = AffineMap::get(numDims, numSymbols, affCombiner(d0, d1));
+
// TODO: createOrFold when available.
Operation *op =
makeComposedAffineApply(ScopedContext::getBuilder(),
ScopedContext::getLocation(), map, operands)
.getOperation();
assert(op->getNumResults() == 1 && "Expected single result AffineApply");
- return ValueHandle(op->getResult(0));
+ return op->getResult(0);
}
template <typename IOp, typename FOp>
-static ValueHandle createBinaryHandle(
- ValueHandle lhs, ValueHandle rhs,
+static Value createBinaryHandle(
+ Value lhs, Value rhs,
function_ref<AffineExpr(AffineExpr, AffineExpr)> affCombiner) {
- auto thisType = lhs.getValue().getType();
- auto thatType = rhs.getValue().getType();
+ auto thisType = lhs.getType();
+ auto thatType = rhs.getType();
assert(thisType == thatType && "cannot mix types in operators");
(void)thisType;
(void)thatType;
if (thisType.isIndex()) {
return createBinaryIndexHandle(lhs, rhs, affCombiner);
} else if (thisType.isSignlessInteger()) {
- return createBinaryHandle<IOp>(lhs, rhs);
+ return ValueBuilder<IOp>(lhs, rhs);
} else if (thisType.isa<FloatType>()) {
- return createBinaryHandle<FOp>(lhs, rhs);
+ return ValueBuilder<FOp>(lhs, rhs);
} else if (thisType.isa<VectorType>() || thisType.isa<TensorType>()) {
auto aggregateType = thisType.cast<ShapedType>();
if (aggregateType.getElementType().isSignlessInteger())
- return createBinaryHandle<IOp>(lhs, rhs);
+ return ValueBuilder<IOp>(lhs, rhs);
else if (aggregateType.getElementType().isa<FloatType>())
- return createBinaryHandle<FOp>(lhs, rhs);
+ return ValueBuilder<FOp>(lhs, rhs);
}
- llvm_unreachable("failed to create a ValueHandle");
+ llvm_unreachable("failed to create a Value");
}
-ValueHandle mlir::edsc::op::operator+(ValueHandle lhs, ValueHandle rhs) {
+Value mlir::edsc::op::operator+(Value lhs, Value rhs) {
return createBinaryHandle<AddIOp, AddFOp>(
lhs, rhs, [](AffineExpr d0, AffineExpr d1) { return d0 + d1; });
}
-ValueHandle mlir::edsc::op::operator-(ValueHandle lhs, ValueHandle rhs) {
+Value mlir::edsc::op::operator-(Value lhs, Value rhs) {
return createBinaryHandle<SubIOp, SubFOp>(
lhs, rhs, [](AffineExpr d0, AffineExpr d1) { return d0 - d1; });
}
-ValueHandle mlir::edsc::op::operator*(ValueHandle lhs, ValueHandle rhs) {
+Value mlir::edsc::op::operator*(Value lhs, Value rhs) {
return createBinaryHandle<MulIOp, MulFOp>(
lhs, rhs, [](AffineExpr d0, AffineExpr d1) { return d0 * d1; });
}
-ValueHandle mlir::edsc::op::operator/(ValueHandle lhs, ValueHandle rhs) {
+Value mlir::edsc::op::operator/(Value lhs, Value rhs) {
return createBinaryHandle<SignedDivIOp, DivFOp>(
lhs, rhs, [](AffineExpr d0, AffineExpr d1) -> AffineExpr {
llvm_unreachable("only exprs of non-index type support operator/");
});
}
-ValueHandle mlir::edsc::op::operator%(ValueHandle lhs, ValueHandle rhs) {
+Value mlir::edsc::op::operator%(Value lhs, Value rhs) {
return createBinaryHandle<SignedRemIOp, RemFOp>(
lhs, rhs, [](AffineExpr d0, AffineExpr d1) { return d0 % d1; });
}
-ValueHandle mlir::edsc::op::floorDiv(ValueHandle lhs, ValueHandle rhs) {
+Value mlir::edsc::op::floorDiv(Value lhs, Value rhs) {
return createBinaryIndexHandle(
lhs, rhs, [](AffineExpr d0, AffineExpr d1) { return d0.floorDiv(d1); });
}
-ValueHandle mlir::edsc::op::ceilDiv(ValueHandle lhs, ValueHandle rhs) {
+Value mlir::edsc::op::ceilDiv(Value lhs, Value rhs) {
return createBinaryIndexHandle(
lhs, rhs, [](AffineExpr d0, AffineExpr d1) { return d0.ceilDiv(d1); });
}
-ValueHandle mlir::edsc::op::operator!(ValueHandle value) {
- assert(value.getType().isInteger(1) && "expected boolean expression");
- return ValueHandle::create<ConstantIntOp>(1, 1) - value;
-}
-
-ValueHandle mlir::edsc::op::operator&&(ValueHandle lhs, ValueHandle rhs) {
+Value mlir::edsc::op::operator&&(Value lhs, Value rhs) {
assert(lhs.getType().isInteger(1) && "expected boolean expression on LHS");
assert(rhs.getType().isInteger(1) && "expected boolean expression on RHS");
- return ValueHandle::create<AndOp>(lhs, rhs);
+ return ValueBuilder<AndOp>(lhs, rhs);
}
-ValueHandle mlir::edsc::op::operator||(ValueHandle lhs, ValueHandle rhs) {
+Value mlir::edsc::op::operator||(Value lhs, Value rhs) {
assert(lhs.getType().isInteger(1) && "expected boolean expression on LHS");
assert(rhs.getType().isInteger(1) && "expected boolean expression on RHS");
- return ValueHandle::create<OrOp>(lhs, rhs);
+ return ValueBuilder<OrOp>(lhs, rhs);
}
-static ValueHandle createIComparisonExpr(CmpIPredicate predicate,
- ValueHandle lhs, ValueHandle rhs) {
+static Value createIComparisonExpr(CmpIPredicate predicate, Value lhs,
+ Value rhs) {
auto lhsType = lhs.getType();
auto rhsType = rhs.getType();
(void)lhsType;
@@ -228,13 +213,12 @@ static ValueHandle createIComparisonExpr(CmpIPredicate predicate,
assert((lhsType.isa<IndexType>() || lhsType.isSignlessInteger()) &&
"only integer comparisons are supported");
- auto op = ScopedContext::getBuilder().create<CmpIOp>(
- ScopedContext::getLocation(), predicate, lhs.getValue(), rhs.getValue());
- return ValueHandle(op.getResult());
+ return ScopedContext::getBuilder().create<CmpIOp>(
+ ScopedContext::getLocation(), predicate, lhs, rhs);
}
-static ValueHandle createFComparisonExpr(CmpFPredicate predicate,
- ValueHandle lhs, ValueHandle rhs) {
+static Value createFComparisonExpr(CmpFPredicate predicate, Value lhs,
+ Value rhs) {
auto lhsType = lhs.getType();
auto rhsType = rhs.getType();
(void)lhsType;
@@ -242,25 +226,24 @@ static ValueHandle createFComparisonExpr(CmpFPredicate predicate,
assert(lhsType == rhsType && "cannot mix types in operators");
assert(lhsType.isa<FloatType>() && "only float comparisons are supported");
- auto op = ScopedContext::getBuilder().create<CmpFOp>(
- ScopedContext::getLocation(), predicate, lhs.getValue(), rhs.getValue());
- return ValueHandle(op.getResult());
+ return ScopedContext::getBuilder().create<CmpFOp>(
+ ScopedContext::getLocation(), predicate, lhs, rhs);
}
// All floating point comparison are ordered through EDSL
-ValueHandle mlir::edsc::op::operator==(ValueHandle lhs, ValueHandle rhs) {
+Value mlir::edsc::op::eq(Value lhs, Value rhs) {
auto type = lhs.getType();
return type.isa<FloatType>()
? createFComparisonExpr(CmpFPredicate::OEQ, lhs, rhs)
: createIComparisonExpr(CmpIPredicate::eq, lhs, rhs);
}
-ValueHandle mlir::edsc::op::operator!=(ValueHandle lhs, ValueHandle rhs) {
+Value mlir::edsc::op::ne(Value lhs, Value rhs) {
auto type = lhs.getType();
return type.isa<FloatType>()
? createFComparisonExpr(CmpFPredicate::ONE, lhs, rhs)
: createIComparisonExpr(CmpIPredicate::ne, lhs, rhs);
}
-ValueHandle mlir::edsc::op::operator<(ValueHandle lhs, ValueHandle rhs) {
+Value mlir::edsc::op::operator<(Value lhs, Value rhs) {
auto type = lhs.getType();
return type.isa<FloatType>()
? createFComparisonExpr(CmpFPredicate::OLT, lhs, rhs)
@@ -268,19 +251,19 @@ ValueHandle mlir::edsc::op::operator<(ValueHandle lhs, ValueHandle rhs) {
// TODO(ntv,zinenko): signed by default, how about unsigned?
createIComparisonExpr(CmpIPredicate::slt, lhs, rhs);
}
-ValueHandle mlir::edsc::op::operator<=(ValueHandle lhs, ValueHandle rhs) {
+Value mlir::edsc::op::operator<=(Value lhs, Value rhs) {
auto type = lhs.getType();
return type.isa<FloatType>()
? createFComparisonExpr(CmpFPredicate::OLE, lhs, rhs)
: createIComparisonExpr(CmpIPredicate::sle, lhs, rhs);
}
-ValueHandle mlir::edsc::op::operator>(ValueHandle lhs, ValueHandle rhs) {
+Value mlir::edsc::op::operator>(Value lhs, Value rhs) {
auto type = lhs.getType();
return type.isa<FloatType>()
? createFComparisonExpr(CmpFPredicate::OGT, lhs, rhs)
: createIComparisonExpr(CmpIPredicate::sgt, lhs, rhs);
}
-ValueHandle mlir::edsc::op::operator>=(ValueHandle lhs, ValueHandle rhs) {
+Value mlir::edsc::op::operator>=(Value lhs, Value rhs) {
auto type = lhs.getType();
return type.isa<FloatType>()
? createFComparisonExpr(CmpFPredicate::OGE, lhs, rhs)
diff --git a/mlir/lib/Dialect/GPU/Transforms/MemoryPromotion.cpp b/mlir/lib/Dialect/GPU/Transforms/MemoryPromotion.cpp
index b5bf47ccc21f..e9f44d209021 100644
--- a/mlir/lib/Dialect/GPU/Transforms/MemoryPromotion.cpp
+++ b/mlir/lib/Dialect/GPU/Transforms/MemoryPromotion.cpp
@@ -44,14 +44,14 @@ static void insertCopyLoops(OpBuilder &builder, Location loc,
MemRefBoundsCapture &bounds, Value from, Value to) {
// Create EDSC handles for bounds.
unsigned rank = bounds.rank();
- SmallVector<ValueHandle, 4> lbs, ubs, steps;
+ SmallVector<Value, 4> lbs, ubs, steps;
// Make sure we have enough loops to use all thread dimensions, these trivial
// loops should be outermost and therefore inserted first.
if (rank < GPUDialect::getNumWorkgroupDimensions()) {
unsigned extraLoops = GPUDialect::getNumWorkgroupDimensions() - rank;
- ValueHandle zero = std_constant_index(0);
- ValueHandle one = std_constant_index(1);
+ Value zero = std_constant_index(0);
+ Value one = std_constant_index(1);
lbs.resize(extraLoops, zero);
ubs.resize(extraLoops, one);
steps.resize(extraLoops, one);
@@ -78,9 +78,8 @@ static void insertCopyLoops(OpBuilder &builder, Location loc,
}
// Produce the loop nest with copies.
- SmallVector<ValueHandle, 8> ivs(lbs.size(), ValueHandle(indexType));
- auto ivPtrs = makeHandlePointers(MutableArrayRef<ValueHandle>(ivs));
- LoopNestBuilder(ivPtrs, lbs, ubs, steps)([&]() {
+ SmallVector<Value, 8> ivs(lbs.size());
+ LoopNestBuilder(ivs, lbs, ubs, steps)([&]() {
auto activeIvs = llvm::makeArrayRef(ivs).take_back(rank);
StdIndexedValue fromHandle(from), toHandle(to);
toHandle(activeIvs) = fromHandle(activeIvs);
@@ -90,8 +89,8 @@ static void insertCopyLoops(OpBuilder &builder, Location loc,
for (auto en :
llvm::enumerate(llvm::reverse(llvm::makeArrayRef(ivs).take_back(
GPUDialect::getNumWorkgroupDimensions())))) {
- auto loop = cast<loop::ForOp>(
- en.value().getValue().getParentRegion()->getParentOp());
+ Value v = en.value();
+ auto loop = cast<loop::ForOp>(v.getParentRegion()->getParentOp());
mapLoopToProcessorIds(loop, {threadIds[en.index()]},
{blockDims[en.index()]});
}
diff --git a/mlir/lib/Dialect/Linalg/EDSC/Builders.cpp b/mlir/lib/Dialect/Linalg/EDSC/Builders.cpp
index 4a775f5cb296..ed0b2d66da61 100644
--- a/mlir/lib/Dialect/Linalg/EDSC/Builders.cpp
+++ b/mlir/lib/Dialect/Linalg/EDSC/Builders.cpp
@@ -21,69 +21,61 @@ using namespace mlir::edsc::intrinsics;
using namespace mlir::linalg;
using namespace mlir::loop;
-mlir::edsc::LoopRangeBuilder::LoopRangeBuilder(ValueHandle *iv,
- ValueHandle range) {
+mlir::edsc::LoopRangeBuilder::LoopRangeBuilder(Value *iv, Value range) {
assert(range.getType() && "expected !linalg.range type");
- assert(range.getValue().getDefiningOp() &&
- "need operations to extract range parts");
- auto rangeOp = cast<RangeOp>(range.getValue().getDefiningOp());
+ assert(range.getDefiningOp() && "need operations to extract range parts");
+ auto rangeOp = cast<RangeOp>(range.getDefiningOp());
auto lb = rangeOp.min();
auto ub = rangeOp.max();
auto step = rangeOp.step();
auto forOp = OperationHandle::createOp<ForOp>(lb, ub, step);
- *iv = ValueHandle(forOp.getInductionVar());
+ *iv = forOp.getInductionVar();
auto *body = forOp.getBody();
enter(body, /*prev=*/1);
}
-mlir::edsc::LoopRangeBuilder::LoopRangeBuilder(ValueHandle *iv,
+mlir::edsc::LoopRangeBuilder::LoopRangeBuilder(Value *iv,
SubViewOp::Range range) {
auto forOp =
OperationHandle::createOp<ForOp>(range.offset, range.size, range.stride);
- *iv = ValueHandle(forOp.getInductionVar());
+ *iv = forOp.getInductionVar();
auto *body = forOp.getBody();
enter(body, /*prev=*/1);
}
-ValueHandle
-mlir::edsc::LoopRangeBuilder::operator()(std::function<void(void)> fun) {
+Value mlir::edsc::LoopRangeBuilder::operator()(std::function<void(void)> fun) {
if (fun)
fun();
exit();
- return ValueHandle::null();
+ return Value();
}
mlir::edsc::LoopNestRangeBuilder::LoopNestRangeBuilder(
- ArrayRef<ValueHandle *> ivs, ArrayRef<SubViewOp::Range> ranges) {
+ MutableArrayRef<Value> ivs, ArrayRef<SubViewOp::Range> ranges) {
loops.reserve(ranges.size());
for (unsigned i = 0, e = ranges.size(); i < e; ++i) {
- loops.emplace_back(ivs[i], ranges[i]);
+ loops.emplace_back(&ivs[i], ranges[i]);
}
assert(loops.size() == ivs.size() && "Mismatch loops vs ivs size");
}
mlir::edsc::LoopNestRangeBuilder::LoopNestRangeBuilder(
- ArrayRef<ValueHandle *> ivs, ArrayRef<ValueHandle> ranges) {
+ MutableArrayRef<Value> ivs, ArrayRef<Value> ranges) {
loops.reserve(ranges.size());
for (unsigned i = 0, e = ranges.size(); i < e; ++i) {
- loops.emplace_back(ivs[i], ranges[i]);
+ loops.emplace_back(&ivs[i], ranges[i]);
}
assert(loops.size() == ivs.size() && "Mismatch loops vs ivs size");
}
-mlir::edsc::LoopNestRangeBuilder::LoopNestRangeBuilder(
- ArrayRef<ValueHandle *> ivs, ArrayRef<Value> ranges)
- : LoopNestRangeBuilder(
- ivs, SmallVector<ValueHandle, 4>(ranges.begin(), ranges.end())) {}
-
-ValueHandle LoopNestRangeBuilder::LoopNestRangeBuilder::operator()(
+Value LoopNestRangeBuilder::LoopNestRangeBuilder::operator()(
std::function<void(void)> fun) {
if (fun)
fun();
for (auto &lit : reverse(loops)) {
lit({});
}
- return ValueHandle::null();
+ return Value();
}
namespace mlir {
@@ -91,15 +83,15 @@ namespace edsc {
template <>
GenericLoopNestRangeBuilder<loop::ForOp>::GenericLoopNestRangeBuilder(
- ArrayRef<edsc::ValueHandle *> ivs, ArrayRef<Value> ranges) {
+ MutableArrayRef<Value> ivs, ArrayRef<Value> ranges) {
builder = std::make_unique<LoopNestRangeBuilder>(ivs, ranges);
}
template <>
GenericLoopNestRangeBuilder<AffineForOp>::GenericLoopNestRangeBuilder(
- ArrayRef<ValueHandle *> ivs, ArrayRef<Value> ranges) {
- SmallVector<ValueHandle, 4> lbs;
- SmallVector<ValueHandle, 4> ubs;
+ MutableArrayRef<Value> ivs, ArrayRef<Value> ranges) {
+ SmallVector<Value, 4> lbs;
+ SmallVector<Value, 4> ubs;
SmallVector<int64_t, 4> steps;
for (Value range : ranges) {
assert(range.getType() && "expected linalg.range type");
@@ -114,8 +106,8 @@ GenericLoopNestRangeBuilder<AffineForOp>::GenericLoopNestRangeBuilder(
template <>
GenericLoopNestRangeBuilder<loop::ParallelOp>::GenericLoopNestRangeBuilder(
- ArrayRef<ValueHandle *> ivs, ArrayRef<Value> ranges) {
- SmallVector<ValueHandle, 4> lbs, ubs, steps;
+ MutableArrayRef<Value> ivs, ArrayRef<Value> ranges) {
+ SmallVector<Value, 4> lbs, ubs, steps;
for (Value range : ranges) {
assert(range.getType() && "expected linalg.range type");
assert(range.getDefiningOp() && "need operations to extract range parts");
@@ -197,10 +189,9 @@ Operation *mlir::edsc::makeGenericLinalgOp(
OpBuilder opBuilder(op);
ScopedContext scope(opBuilder, op->getLoc());
BlockHandle b;
- auto handles = makeValueHandles(blockTypes);
- BlockBuilder(&b, op->getRegion(0),
- makeHandlePointers(MutableArrayRef<ValueHandle>(handles)))(
- [&] { regionBuilder(b.getBlock()->getArguments()); });
+ SmallVector<Value, 8> handles(blockTypes.size());
+ BlockBuilder(&b, op->getRegion(0), blockTypes,
+ handles)([&] { regionBuilder(b.getBlock()->getArguments()); });
assert(op->getRegion(0).getBlocks().size() == 1);
return op;
}
@@ -209,16 +200,16 @@ void mlir::edsc::ops::mulRegionBuilder(ArrayRef<BlockArgument> args) {
using edsc::op::operator+;
using edsc::op::operator*;
assert(args.size() == 2 && "expected 2 block arguments");
- ValueHandle a(args[0]), b(args[1]);
- linalg_yield((a * b).getValue());
+ Value a(args[0]), b(args[1]);
+ linalg_yield(a * b);
}
void mlir::edsc::ops::macRegionBuilder(ArrayRef<BlockArgument> args) {
using edsc::op::operator+;
using edsc::op::operator*;
assert(args.size() == 3 && "expected 3 block arguments");
- ValueHandle a(args[0]), b(args[1]), c(args[2]);
- linalg_yield((c + a * b).getValue());
+ Value a(args[0]), b(args[1]), c(args[2]);
+ linalg_yield(c + a * b);
}
Operation *mlir::edsc::ops::linalg_generic_pointwise(
@@ -228,14 +219,14 @@ Operation *mlir::edsc::ops::linalg_generic_pointwise(
if (O.getType().isa<RankedTensorType>()) {
auto fun = [&unaryOp](ArrayRef<BlockArgument> args) {
assert(args.size() == 1 && "expected 1 block arguments");
- ValueHandle a(args[0]);
+ Value a(args[0]);
linalg_yield(unaryOp(a));
};
return makeGenericLinalgOp(iterTypes, {I}, {O}, fun);
}
auto fun = [&unaryOp](ArrayRef<BlockArgument> args) {
assert(args.size() == 2 && "expected 2 block arguments");
- ValueHandle a(args[0]);
+ Value a(args[0]);
linalg_yield(unaryOp(a));
};
return makeGenericLinalgOp(iterTypes, {I}, {O}, fun);
@@ -243,8 +234,7 @@ Operation *mlir::edsc::ops::linalg_generic_pointwise(
Operation *mlir::edsc::ops::linalg_generic_pointwise_tanh(StructuredIndexed I,
StructuredIndexed O) {
- UnaryPointwiseOpBuilder unOp(
- [](ValueHandle a) -> Value { return std_tanh(a); });
+ UnaryPointwiseOpBuilder unOp([](Value a) -> Value { return std_tanh(a); });
return linalg_generic_pointwise(unOp, I, O);
}
@@ -257,14 +247,14 @@ Operation *mlir::edsc::ops::linalg_generic_pointwise(
if (O.getType().isa<RankedTensorType>()) {
auto fun = [&binaryOp](ArrayRef<BlockArgument> args) {
assert(args.size() == 2 && "expected 2 block arguments");
- ValueHandle a(args[0]), b(args[1]);
+ Value a(args[0]), b(args[1]);
linalg_yield(binaryOp(a, b));
};
return makeGenericLinalgOp(iterTypes, {I1, I2}, {O}, fun);
}
auto fun = [&binaryOp](ArrayRef<BlockArgument> args) {
assert(args.size() == 3 && "expected 3 block arguments");
- ValueHandle a(args[0]), b(args[1]);
+ Value a(args[0]), b(args[1]);
linalg_yield(binaryOp(a, b));
};
return makeGenericLinalgOp(iterTypes, {I1, I2}, {O}, fun);
@@ -275,23 +265,22 @@ Operation *mlir::edsc::ops::linalg_generic_pointwise_add(StructuredIndexed I1,
StructuredIndexed O) {
using edsc::op::operator+;
BinaryPointwiseOpBuilder binOp(
- [](ValueHandle a, ValueHandle b) -> Value { return a + b; });
+ [](Value a, Value b) -> Value { return a + b; });
return linalg_generic_pointwise(binOp, I1, I2, O);
}
Operation *mlir::edsc::ops::linalg_generic_pointwise_max(StructuredIndexed I1,
StructuredIndexed I2,
StructuredIndexed O) {
- BinaryPointwiseOpBuilder binOp([](ValueHandle a, ValueHandle b) -> Value {
+ BinaryPointwiseOpBuilder binOp([](Value a, Value b) -> Value {
using edsc::op::operator>;
- return std_select(a > b, a, b).getValue();
+ return std_select(a > b, a, b);
});
return linalg_generic_pointwise(binOp, I1, I2, O);
}
Operation *
-mlir::edsc::ops::linalg_generic_matmul(ValueHandle vA, ValueHandle vB,
- ValueHandle vC,
+mlir::edsc::ops::linalg_generic_matmul(Value vA, Value vB, Value vC,
MatmulRegionBuilder regionBuilder) {
// clang-format off
AffineExpr m, n, k;
@@ -306,8 +295,7 @@ mlir::edsc::ops::linalg_generic_matmul(ValueHandle vA, ValueHandle vB,
}
Operation *
-mlir::edsc::ops::linalg_generic_matmul(ValueHandle vA, ValueHandle vB,
- RankedTensorType tC,
+mlir::edsc::ops::linalg_generic_matmul(Value vA, Value vB, RankedTensorType tC,
MatmulRegionBuilder regionBuilder) {
// clang-format off
AffineExpr m, n, k;
@@ -322,8 +310,8 @@ mlir::edsc::ops::linalg_generic_matmul(ValueHandle vA, ValueHandle vB,
}
Operation *
-mlir::edsc::ops::linalg_generic_matmul(ValueHandle vA, ValueHandle vB,
- ValueHandle vC, RankedTensorType tD,
+mlir::edsc::ops::linalg_generic_matmul(Value vA, Value vB, Value vC,
+ RankedTensorType tD,
MatmulRegionBuilder regionBuilder) {
// clang-format off
AffineExpr m, n, k;
@@ -337,9 +325,8 @@ mlir::edsc::ops::linalg_generic_matmul(ValueHandle vA, ValueHandle vB,
// clang-format on
}
-Operation *mlir::edsc::ops::linalg_generic_conv_nhwc(ValueHandle vI,
- ValueHandle vW,
- ValueHandle vO,
+Operation *mlir::edsc::ops::linalg_generic_conv_nhwc(Value vI, Value vW,
+ Value vO,
ArrayRef<int> strides,
ArrayRef<int> dilations) {
MLIRContext *ctx = ScopedContext::getContext();
@@ -373,8 +360,8 @@ Operation *mlir::edsc::ops::linalg_generic_conv_nhwc(ValueHandle vI,
}
Operation *mlir::edsc::ops::linalg_generic_dilated_conv_nhwc(
- ValueHandle vI, ValueHandle vW, ValueHandle vO, int depth_multiplier,
- ArrayRef<int> strides, ArrayRef<int> dilations) {
+ Value vI, Value vW, Value vO, int depth_multiplier, ArrayRef<int> strides,
+ ArrayRef<int> dilations) {
MLIRContext *ctx = ScopedContext::getContext();
// TODO(ntv) some template magic to make everything rank-polymorphic.
assert((dilations.empty() || dilations.size() == 2) && "only 2-D conv atm");
diff --git a/mlir/lib/Dialect/Linalg/Transforms/Fusion.cpp b/mlir/lib/Dialect/Linalg/Transforms/Fusion.cpp
index a04cf90d2069..b2100419a114 100644
--- a/mlir/lib/Dialect/Linalg/Transforms/Fusion.cpp
+++ b/mlir/lib/Dialect/Linalg/Transforms/Fusion.cpp
@@ -35,7 +35,7 @@ using namespace mlir::edsc;
using namespace mlir::edsc::intrinsics;
using namespace mlir::linalg;
-using folded_std_constant_index = folded::ValueBuilder<ConstantIndexOp>;
+using folded_std_constant_index = FoldedValueBuilder<ConstantIndexOp>;
using llvm::dbgs;
diff --git a/mlir/lib/Dialect/Linalg/Transforms/LinalgToLoops.cpp b/mlir/lib/Dialect/Linalg/Transforms/LinalgToLoops.cpp
index 7f39139d69e0..88678e5d085c 100644
--- a/mlir/lib/Dialect/Linalg/Transforms/LinalgToLoops.cpp
+++ b/mlir/lib/Dialect/Linalg/Transforms/LinalgToLoops.cpp
@@ -29,17 +29,16 @@ using namespace mlir::edsc::intrinsics;
using namespace mlir::linalg;
using edsc::op::operator+;
-using edsc::op::operator==;
-using mlir::edsc::intrinsics::detail::ValueHandleArray;
-static SmallVector<ValueHandle, 8>
-makeCanonicalAffineApplies(OpBuilder &b, Location loc, AffineMap map,
- ArrayRef<Value> vals) {
+static SmallVector<Value, 8> makeCanonicalAffineApplies(OpBuilder &b,
+ Location loc,
+ AffineMap map,
+ ArrayRef<Value> vals) {
if (map.isEmpty())
return {};
assert(map.getNumSymbols() == 0);
assert(map.getNumInputs() == vals.size());
- SmallVector<ValueHandle, 8> res;
+ SmallVector<Value, 8> res;
res.reserve(map.getNumResults());
auto dims = map.getNumDims();
for (auto e : map.getResults()) {
@@ -80,10 +79,10 @@ SmallVector<Value, 4> emitLoopRanges(OpBuilder &b, Location loc, AffineMap map,
}
template <typename OpType>
-static void inlineRegionAndEmitStdStore(OpType op,
- ArrayRef<Value> indexedValues,
- ArrayRef<ValueHandleArray> indexing,
- ArrayRef<Value> outputBuffers) {
+static void
+inlineRegionAndEmitStdStore(OpType op, ArrayRef<Value> indexedValues,
+ ArrayRef<SmallVector<Value, 8>> indexing,
+ ArrayRef<Value> outputBuffers) {
auto &b = ScopedContext::getBuilder();
auto &block = op.region().front();
BlockAndValueMapping map;
@@ -99,25 +98,27 @@ static void inlineRegionAndEmitStdStore(OpType op,
"expected an yield op in the end of the region");
for (unsigned i = 0, e = terminator.getNumOperands(); i < e; ++i) {
std_store(map.lookupOrDefault(terminator.getOperand(i)), outputBuffers[i],
- indexing[i]);
+ ArrayRef<Value>{indexing[i].begin(), indexing[i].end()});
}
}
// Returns a pair that contains input indices and output indices of a
// SingleInputPoolingOp `op`.
+struct InputAndOutputIndices {
+ SmallVector<Value, 8> inputs;
+ SmallVector<Value, 8> outputs;
+};
template <typename SingleInputPoolingOp>
-static std::pair<SmallVector<ValueHandle, 8>, SmallVector<ValueHandle, 8>>
-getInputAndOutputIndices(ArrayRef<Value> allIvs, SingleInputPoolingOp op) {
+static InputAndOutputIndices getInputAndOutputIndices(ArrayRef<Value> allIvs,
+ SingleInputPoolingOp op) {
auto &b = ScopedContext::getBuilder();
auto loc = ScopedContext::getLocation();
auto mapsRange = op.indexing_maps().template getAsRange<AffineMapAttr>();
auto maps = llvm::to_vector<8>(
llvm::map_range(mapsRange, [](AffineMapAttr a) { return a.getValue(); }));
- SmallVector<ValueHandle, 8> iIdx(
- makeCanonicalAffineApplies(b, loc, maps[0], allIvs));
- SmallVector<ValueHandle, 8> oIdx(
- makeCanonicalAffineApplies(b, loc, maps[2], allIvs));
- return {iIdx, oIdx};
+ return InputAndOutputIndices{
+ makeCanonicalAffineApplies(b, loc, maps[0], allIvs),
+ makeCanonicalAffineApplies(b, loc, maps[2], allIvs)};
}
namespace {
@@ -150,8 +151,8 @@ class LinalgScopedEmitter<IndexedValueType, CopyOp> {
permuteIvs(allIvs.take_front(nPar), copyOp.inputPermutation());
auto outputIvs =
permuteIvs(allIvs.take_front(nPar), copyOp.outputPermutation());
- SmallVector<ValueHandle, 8> iivs(inputIvs.begin(), inputIvs.end());
- SmallVector<ValueHandle, 8> oivs(outputIvs.begin(), outputIvs.end());
+ SmallVector<Value, 8> iivs(inputIvs.begin(), inputIvs.end());
+ SmallVector<Value, 8> oivs(outputIvs.begin(), outputIvs.end());
IndexedValueType O(copyOp.getOutputBuffer(0)), I(copyOp.getInput(0));
// Emit the proper scalar assignment, whether we are dealing with a 0-D or
// an n-D loop nest; with or without permutations.
@@ -170,13 +171,11 @@ class LinalgScopedEmitter<IndexedValueType, FillOp> {
"expected linalg op with buffer semantics");
auto nPar = fillOp.getNumParallelLoops();
assert(nPar == allIvs.size());
- auto ivs =
- SmallVector<ValueHandle, 4>(allIvs.begin(), allIvs.begin() + nPar);
+ auto ivs = SmallVector<Value, 4>(allIvs.begin(), allIvs.begin() + nPar);
IndexedValueType O(fillOp.getOutputBuffer(0));
// Emit the proper scalar assignment, whether we are dealing with a 0-D or
// an n-D loop nest; with or without permutations.
- nPar > 0 ? O(ivs) = ValueHandle(fillOp.value())
- : O() = ValueHandle(fillOp.value());
+ nPar > 0 ? O(ivs) = fillOp.value() : O() = fillOp.value();
}
};
@@ -187,7 +186,7 @@ class LinalgScopedEmitter<IndexedValueType, DotOp> {
assert(dotOp.hasBufferSemantics() &&
"expected linalg op with buffer semantics");
assert(allIvs.size() == 1);
- ValueHandle r_i(allIvs[0]);
+ Value r_i(allIvs[0]);
IndexedValueType A(dotOp.getInput(0)), B(dotOp.getInput(1)),
C(dotOp.getOutputBuffer(0));
// Emit scalar form.
@@ -203,7 +202,7 @@ class LinalgScopedEmitter<IndexedValueType, MatvecOp> {
assert(matvecOp.hasBufferSemantics() &&
"expected linalg op with buffer semantics");
assert(allIvs.size() == 2);
- ValueHandle i(allIvs[0]), r_j(allIvs[1]);
+ Value i(allIvs[0]), r_j(allIvs[1]);
IndexedValueType A(matvecOp.getInput(0)), B(matvecOp.getInput(1)),
C(matvecOp.getOutputBuffer(0));
// Emit scalar form.
@@ -219,7 +218,7 @@ class LinalgScopedEmitter<IndexedValueType, MatmulOp> {
assert(matmulOp.hasBufferSemantics() &&
"expected linalg op with buffer semantics");
assert(allIvs.size() == 3);
- ValueHandle i(allIvs[0]), j(allIvs[1]), r_k(allIvs[2]);
+ Value i(allIvs[0]), j(allIvs[1]), r_k(allIvs[2]);
IndexedValueType A(matmulOp.getInput(0)), B(matmulOp.getInput(1)),
C(matmulOp.getOutputBuffer(0));
// Emit scalar form.
@@ -232,16 +231,16 @@ class LinalgScopedEmitter<IndexedValueType, ConvOp> {
public:
/// Returns the input value of convOp. If the indices in `imIdx` is out of
/// boundary, returns 0 instead.
- static ValueHandle getConvOpInput(ConvOp convOp, IndexedValueType im,
- ArrayRef<ValueHandle> imIdx) {
+ static Value getConvOpInput(ConvOp convOp, IndexedValueType im,
+ MutableArrayRef<Value> imIdx) {
// TODO(ntv): add a level of indirection to linalg.generic.
if (!convOp.padding())
return im(imIdx);
auto *context = ScopedContext::getContext();
- ValueHandle zeroIndex = std_constant_index(0);
- SmallVector<ValueHandle, 8> conds;
- SmallVector<ValueHandle, 8> clampedImIdx;
+ Value zeroIndex = std_constant_index(0);
+ SmallVector<Value, 8> conds;
+ SmallVector<Value, 8> clampedImIdx;
for (auto iter : llvm::enumerate(imIdx)) {
int idx = iter.index();
auto dim = iter.value();
@@ -254,12 +253,12 @@ class LinalgScopedEmitter<IndexedValueType, ConvOp> {
using edsc::op::operator<;
using edsc::op::operator>=;
using edsc::op::operator||;
- ValueHandle leftOutOfBound = dim < zeroIndex;
+ Value leftOutOfBound = dim < zeroIndex;
if (conds.empty())
conds.push_back(leftOutOfBound);
else
conds.push_back(conds.back() || leftOutOfBound);
- ValueHandle rightBound = std_dim(convOp.input(), idx);
+ Value rightBound = std_dim(convOp.input(), idx);
conds.push_back(conds.back() || (dim >= rightBound));
// When padding is involved, the indices will only be shifted to negative,
@@ -274,10 +273,10 @@ class LinalgScopedEmitter<IndexedValueType, ConvOp> {
auto b = ScopedContext::getBuilder();
Type type = convOp.input().getType().cast<MemRefType>().getElementType();
- ValueHandle zero = std_constant(type, b.getZeroAttr(type));
- ValueHandle readInput = im(clampedImIdx);
+ Value zero = std_constant(type, b.getZeroAttr(type));
+ Value readInput = im(clampedImIdx);
return conds.empty() ? readInput
- : std_select(conds.back(), zero, readInput);
+ : (Value)std_select(conds.back(), zero, readInput);
}
static void emitScalarImplementation(ArrayRef<Value> allIvs, ConvOp convOp) {
@@ -288,16 +287,16 @@ class LinalgScopedEmitter<IndexedValueType, ConvOp> {
auto mapsRange = convOp.indexing_maps().getAsRange<AffineMapAttr>();
auto maps = llvm::to_vector<8>(llvm::map_range(
mapsRange, [](AffineMapAttr a) { return a.getValue(); }));
- SmallVector<ValueHandle, 8> fIdx(
+ SmallVector<Value, 8> fIdx(
makeCanonicalAffineApplies(b, loc, maps[0], allIvs));
- SmallVector<ValueHandle, 8> imIdx(
+ SmallVector<Value, 8> imIdx(
makeCanonicalAffineApplies(b, loc, maps[1], allIvs));
- SmallVector<ValueHandle, 8> oIdx(
+ SmallVector<Value, 8> oIdx(
makeCanonicalAffineApplies(b, loc, maps[2], allIvs));
IndexedValueType F(convOp.filter()), I(convOp.input()), O(convOp.output());
// Emit scalar form.
- ValueHandle paddedInput = getConvOpInput(convOp, I, imIdx);
+ Value paddedInput = getConvOpInput(convOp, I, imIdx);
O(oIdx) += F(fIdx) * paddedInput;
}
};
@@ -308,15 +307,12 @@ class LinalgScopedEmitter<IndexedValueType, PoolingMaxOp> {
static void emitScalarImplementation(ArrayRef<Value> allIvs,
PoolingMaxOp op) {
auto indices = getInputAndOutputIndices(allIvs, op);
- ValueHandleArray iIdx(indices.first);
- ValueHandleArray oIdx(indices.second);
-
// Emit scalar form.
- ValueHandle lhs = std_load(op.output(), oIdx);
- ValueHandle rhs = std_load(op.input(), iIdx);
+ Value lhs = std_load(op.output(), indices.outputs);
+ Value rhs = std_load(op.input(), indices.inputs);
using edsc::op::operator>;
- ValueHandle maxValue = std_select(lhs > rhs, lhs, rhs);
- std_store(maxValue, op.output(), oIdx);
+ Value maxValue = std_select(lhs > rhs, lhs, rhs);
+ std_store(maxValue, op.output(), indices.outputs);
}
};
@@ -326,15 +322,12 @@ class LinalgScopedEmitter<IndexedValueType, PoolingMinOp> {
static void emitScalarImplementation(ArrayRef<Value> allIvs,
PoolingMinOp op) {
auto indices = getInputAndOutputIndices(allIvs, op);
- ValueHandleArray iIdx(indices.first);
- ValueHandleArray oIdx(indices.second);
-
// Emit scalar form.
- ValueHandle lhs = std_load(op.output(), oIdx);
- ValueHandle rhs = std_load(op.input(), iIdx);
+ Value lhs = std_load(op.output(), indices.outputs);
+ Value rhs = std_load(op.input(), indices.inputs);
using edsc::op::operator<;
- ValueHandle minValue = std_select(lhs < rhs, lhs, rhs);
- std_store(minValue, op.output(), oIdx);
+ Value minValue = std_select(lhs < rhs, lhs, rhs);
+ std_store(minValue, op.output(), indices.outputs);
}
};
@@ -344,12 +337,10 @@ class LinalgScopedEmitter<IndexedValueType, PoolingSumOp> {
static void emitScalarImplementation(ArrayRef<Value> allIvs,
PoolingSumOp op) {
auto indices = getInputAndOutputIndices(allIvs, op);
- SmallVector<ValueHandle, 8> iIdx = indices.first;
- SmallVector<ValueHandle, 8> oIdx = indices.second;
IndexedValueType input(op.input()), output(op.output());
// Emit scalar form.
- output(oIdx) += input(iIdx);
+ output(indices.outputs) += input(indices.inputs);
}
};
@@ -392,15 +383,14 @@ class LinalgScopedEmitter<IndexedValueType, GenericOp> {
"expected linalg op with buffer semantics");
auto b = ScopedContext::getBuilder();
auto loc = ScopedContext::getLocation();
- using edsc::intrinsics::detail::ValueHandleArray;
unsigned nInputs = genericOp.getNumInputs();
unsigned nOutputs = genericOp.getNumOutputs();
SmallVector<Value, 4> indexedValues(nInputs + nOutputs);
// 1.a. Emit std_load from input views.
for (unsigned i = 0; i < nInputs; ++i) {
- ValueHandleArray indexing(makeCanonicalAffineApplies(
- b, loc, genericOp.getInputIndexingMap(i), allIvs));
+ auto indexing = makeCanonicalAffineApplies(
+ b, loc, genericOp.getInputIndexingMap(i), allIvs);
indexedValues[i] = std_load(genericOp.getInput(i), indexing);
}
@@ -409,18 +399,18 @@ class LinalgScopedEmitter<IndexedValueType, GenericOp> {
// region has no uses.
for (unsigned i = 0; i < nOutputs; ++i) {
Value output = genericOp.getOutputBuffer(i);
- ValueHandleArray indexing(makeCanonicalAffineApplies(
- b, loc, genericOp.getOutputIndexingMap(i), allIvs));
+ auto indexing = makeCanonicalAffineApplies(
+ b, loc, genericOp.getOutputIndexingMap(i), allIvs);
indexedValues[nInputs + i] = std_load(output, indexing);
}
// TODO(ntv): When a region inliner exists, use it.
// 2. Inline region, currently only works for a single basic block.
// 3. Emit std_store.
- SmallVector<ValueHandleArray, 8> indexing;
+ SmallVector<SmallVector<Value, 8>, 8> indexing;
SmallVector<Value, 8> outputBuffers;
for (unsigned i = 0; i < nOutputs; ++i) {
- indexing.emplace_back(makeCanonicalAffineApplies(
+ indexing.push_back(makeCanonicalAffineApplies(
b, loc, genericOp.getOutputIndexingMap(i), allIvs));
outputBuffers.push_back(genericOp.getOutputBuffer(i));
}
@@ -468,7 +458,6 @@ class LinalgScopedEmitter<IndexedValueType, IndexedGenericOp> {
"expected linalg op with buffer semantics");
auto b = ScopedContext::getBuilder();
auto loc = ScopedContext::getLocation();
- using edsc::intrinsics::detail::ValueHandleArray;
unsigned nInputs = indexedGenericOp.getNumInputs();
unsigned nOutputs = indexedGenericOp.getNumOutputs();
unsigned nLoops = allIvs.size();
@@ -481,26 +470,26 @@ class LinalgScopedEmitter<IndexedValueType, IndexedGenericOp> {
// 1.a. Emit std_load from input views.
for (unsigned i = 0; i < nInputs; ++i) {
Value input = indexedGenericOp.getInput(i);
- ValueHandleArray indexing(makeCanonicalAffineApplies(
- b, loc, indexedGenericOp.getInputIndexingMap(i), allIvs));
+ auto indexing = makeCanonicalAffineApplies(
+ b, loc, indexedGenericOp.getInputIndexingMap(i), allIvs);
indexedValues[nLoops + i] = std_load(input, indexing);
}
// 1.b. Emit std_load from output views.
for (unsigned i = 0; i < nOutputs; ++i) {
Value output = indexedGenericOp.getOutputBuffer(i);
- ValueHandleArray indexing(makeCanonicalAffineApplies(
- b, loc, indexedGenericOp.getOutputIndexingMap(i), allIvs));
+ auto indexing = makeCanonicalAffineApplies(
+ b, loc, indexedGenericOp.getOutputIndexingMap(i), allIvs);
indexedValues[nLoops + nInputs + i] = std_load(output, indexing);
}
// TODO(ntv): When a region inliner exists, use it.
// 2. Inline region, currently only works for a single basic block.
// 3. Emit std_store.
- SmallVector<ValueHandleArray, 8> indexing;
+ SmallVector<SmallVector<Value, 8>, 8> indexing;
SmallVector<Value, 8> outputBuffers;
for (unsigned i = 0; i < nOutputs; ++i) {
- indexing.emplace_back(makeCanonicalAffineApplies(
+ indexing.push_back(makeCanonicalAffineApplies(
b, loc, indexedGenericOp.getOutputIndexingMap(i), allIvs));
outputBuffers.push_back(indexedGenericOp.getOutputBuffer(i));
}
@@ -533,11 +522,8 @@ class GenerateLoopNest {
typename std::conditional<std::is_same<LoopTy, AffineForOp>::value,
AffineIndexedValue, StdIndexedValue>::type;
static void doit(ConcreteOpTy linalgOp, ArrayRef<Value> loopRanges,
- MutableArrayRef<ValueHandle> allIvs) {
- SmallVector<ValueHandle *, 4> allPIvs =
- makeHandlePointers(MutableArrayRef<ValueHandle>(allIvs));
-
- GenericLoopNestRangeBuilder<LoopTy>(allPIvs, loopRanges)([&] {
+ MutableArrayRef<Value> allIvs) {
+ GenericLoopNestRangeBuilder<LoopTy>(allIvs, loopRanges)([&] {
SmallVector<Value, 4> allIvValues(allIvs.begin(), allIvs.end());
LinalgScopedEmitter<IndexedValueTy,
ConcreteOpTy>::emitScalarImplementation(allIvValues,
@@ -555,7 +541,7 @@ class GenerateLoopNest<loop::ParallelOp, ConcreteOpTy> {
using IndexedValueTy = StdIndexedValue;
static void doit(ConcreteOpTy linalgOp, ArrayRef<Value> loopRanges,
- MutableArrayRef<ValueHandle> allIvs) {
+ MutableArrayRef<Value> allIvs) {
// Only generate loop.parallel for outer consecutive "parallel"
// iterator_types.
// TODO(ravishankarm): Generate loop.parallel for all "parallel" iterator
@@ -575,24 +561,18 @@ class GenerateLoopNest<loop::ParallelOp, ConcreteOpTy> {
// If there are no outer parallel loops, then number of loop ops is same as
// the number of loops, and they are all loop.for ops.
auto nLoopOps = (nOuterPar ? nLoops - nOuterPar + 1 : nLoops);
- SmallVector<ValueHandle *, 4> allPIvs =
- makeHandlePointers(MutableArrayRef<ValueHandle>(allIvs));
-
SmallVector<OperationHandle, 4> allLoops(nLoopOps, OperationHandle());
SmallVector<OperationHandle *, 4> allPLoops;
allPLoops.reserve(allLoops.size());
for (OperationHandle &loop : allLoops)
allPLoops.push_back(&loop);
-
- ArrayRef<ValueHandle *> allPIvsRef(allPIvs);
ArrayRef<OperationHandle *> allPLoopsRef(allPLoops);
if (nOuterPar) {
GenericLoopNestRangeBuilder<loop::ParallelOp>(
- allPIvsRef.take_front(nOuterPar),
- loopRanges.take_front(nOuterPar))([&] {
+ allIvs.take_front(nOuterPar), loopRanges.take_front(nOuterPar))([&] {
GenericLoopNestRangeBuilder<loop::ForOp>(
- allPIvsRef.drop_front(nOuterPar),
+ allIvs.drop_front(nOuterPar),
loopRanges.drop_front(nOuterPar))([&] {
SmallVector<Value, 4> allIvValues(allIvs.begin(), allIvs.end());
LinalgScopedEmitter<StdIndexedValue, ConcreteOpTy>::
@@ -602,7 +582,7 @@ class GenerateLoopNest<loop::ParallelOp, ConcreteOpTy> {
} else {
// If there are no parallel loops then fallback to generating all loop.for
// operations.
- GenericLoopNestRangeBuilder<loop::ForOp>(allPIvsRef, loopRanges)([&] {
+ GenericLoopNestRangeBuilder<loop::ForOp>(allIvs, loopRanges)([&] {
SmallVector<Value, 4> allIvValues(allIvs.begin(), allIvs.end());
LinalgScopedEmitter<StdIndexedValue,
ConcreteOpTy>::emitScalarImplementation(allIvValues,
@@ -645,8 +625,7 @@ LinalgOpToLoopsImpl<LoopTy, ConcreteOpTy>::doit(Operation *op,
return LinalgLoops();
}
- SmallVector<ValueHandle, 4> allIvs(nLoops,
- ValueHandle(rewriter.getIndexType()));
+ SmallVector<Value, 4> allIvs(nLoops);
auto loopRanges =
emitLoopRanges(scope.getBuilder(), scope.getLocation(), invertedMap,
getViewSizes(rewriter, linalgOp));
@@ -655,12 +634,12 @@ LinalgOpToLoopsImpl<LoopTy, ConcreteOpTy>::doit(Operation *op,
// Number of loop ops might be
diff erent from the number of ivs since some
// loops like affine.parallel and loop.parallel have multiple ivs.
llvm::SetVector<Operation *> loopSet;
- for (ValueHandle &iv : allIvs) {
- if (!iv.hasValue())
+ for (Value iv : allIvs) {
+ if (!iv)
return {};
// The induction variable is a block argument of the entry block of the
// loop operation.
- BlockArgument ivVal = iv.getValue().dyn_cast<BlockArgument>();
+ BlockArgument ivVal = iv.dyn_cast<BlockArgument>();
if (!ivVal)
return {};
loopSet.insert(ivVal.getOwner()->getParentOp());
diff --git a/mlir/lib/Dialect/Linalg/Transforms/LinalgTransforms.cpp b/mlir/lib/Dialect/Linalg/Transforms/LinalgTransforms.cpp
index 15454a4d6bd4..423c1c10596a 100644
--- a/mlir/lib/Dialect/Linalg/Transforms/LinalgTransforms.cpp
+++ b/mlir/lib/Dialect/Linalg/Transforms/LinalgTransforms.cpp
@@ -16,6 +16,7 @@
#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"
@@ -219,10 +220,6 @@ LogicalResult mlir::linalg::vectorizeLinalgOpPrecondition(Operation *op) {
SmallVector<Value, 0> mlir::linalg::vectorizeLinalgOp(PatternRewriter &rewriter,
Operation *op) {
- using vector_contract = edsc::intrinsics::ValueBuilder<vector::ContractionOp>;
- using vector_broadcast = edsc::intrinsics::ValueBuilder<vector::BroadcastOp>;
- using vector_type_cast = edsc::intrinsics::ValueBuilder<vector::TypeCastOp>;
-
assert(succeeded(vectorizeLinalgOpPrecondition(op)) &&
"DRR failure case must be a precondition");
auto linalgOp = cast<linalg::LinalgOp>(op);
@@ -242,8 +239,8 @@ SmallVector<Value, 0> mlir::linalg::vectorizeLinalgOp(PatternRewriter &rewriter,
"]: Rewrite linalg.fill as vector.broadcast: "
<< *op << ":\n");
auto dstMemrefVec = vector_type_cast(fillOp.getOutputBuffer(0));
- auto dstVec = std_load(dstMemrefVec);
- auto resVec = vector_broadcast(dstVec, fillOp.value());
+ Value dstVec = std_load(dstMemrefVec);
+ auto resVec = vector_broadcast(dstVec.getType(), fillOp.value());
std_store(resVec, dstMemrefVec);
} else {
// Vectorize other ops as vector contraction (currently only matmul).
diff --git a/mlir/lib/Dialect/Linalg/Transforms/Promotion.cpp b/mlir/lib/Dialect/Linalg/Transforms/Promotion.cpp
index 5bde420df076..ca905116d71e 100644
--- a/mlir/lib/Dialect/Linalg/Transforms/Promotion.cpp
+++ b/mlir/lib/Dialect/Linalg/Transforms/Promotion.cpp
@@ -36,11 +36,11 @@ using namespace mlir::loop;
using llvm::SetVector;
-using folded_affine_min = folded::ValueBuilder<AffineMinOp>;
-using folded_linalg_range = folded::ValueBuilder<linalg::RangeOp>;
-using folded_std_dim = folded::ValueBuilder<DimOp>;
-using folded_std_subview = folded::ValueBuilder<SubViewOp>;
-using folded_std_view = folded::ValueBuilder<ViewOp>;
+using folded_affine_min = FoldedValueBuilder<AffineMinOp>;
+using folded_linalg_range = FoldedValueBuilder<linalg::RangeOp>;
+using folded_std_dim = FoldedValueBuilder<DimOp>;
+using folded_std_subview = FoldedValueBuilder<SubViewOp>;
+using folded_std_view = FoldedValueBuilder<ViewOp>;
#define DEBUG_TYPE "linalg-promotion"
@@ -74,8 +74,8 @@ static Value allocBuffer(Type elementType, Value size, bool dynamicBuffers,
if (!dynamicBuffers)
if (auto cst = dyn_cast_or_null<ConstantIndexOp>(size.getDefiningOp()))
return std_alloc(
- MemRefType::get(width * cst.getValue(), IntegerType::get(8, ctx)), {},
- alignment_attr);
+ MemRefType::get(width * cst.getValue(), IntegerType::get(8, ctx)),
+ ValueRange{}, alignment_attr);
Value mul =
folded_std_muli(folder, folded_std_constant_index(folder, width), size);
return std_alloc(MemRefType::get(-1, IntegerType::get(8, ctx)), mul,
@@ -118,7 +118,7 @@ static PromotionInfo promoteFullTileBuffer(OpBuilder &b, Location loc,
auto rangeValue = en.value();
// Try to extract a tight constant
Value size = extractSmallestConstantBoundingSize(b, loc, rangeValue.size);
- allocSize = folded_std_muli(folder, allocSize, size).getValue();
+ allocSize = folded_std_muli(folder, allocSize, size);
fullSizes.push_back(size);
partialSizes.push_back(folded_std_dim(folder, subView, rank));
}
diff --git a/mlir/lib/Dialect/Linalg/Transforms/Tiling.cpp b/mlir/lib/Dialect/Linalg/Transforms/Tiling.cpp
index 87a2015338ca..4dd8c5ad0e50 100644
--- a/mlir/lib/Dialect/Linalg/Transforms/Tiling.cpp
+++ b/mlir/lib/Dialect/Linalg/Transforms/Tiling.cpp
@@ -32,7 +32,7 @@ using namespace mlir::edsc::intrinsics;
using namespace mlir::linalg;
using namespace mlir::loop;
-using folded_affine_min = folded::ValueBuilder<AffineMinOp>;
+using folded_affine_min = FoldedValueBuilder<AffineMinOp>;
#define DEBUG_TYPE "linalg-tiling"
@@ -163,7 +163,7 @@ struct TileCheck : public AffineExprVisitor<TileCheck> {
// TODO(pifon, ntv): Investigate whether mixing implicit and explicit indices
// does not lead to losing information.
static void transformIndexedGenericOpIndices(
- OpBuilder &b, LinalgOp op, ArrayRef<ValueHandle *> pivs,
+ OpBuilder &b, LinalgOp op, SmallVectorImpl<Value> &ivs,
const LoopIndexToRangeIndexMap &loopIndexToRangeIndex) {
assert(op.hasBufferSemantics() && "expected linalg op with buffer semantics");
auto indexedGenericOp = dyn_cast<IndexedGenericOp>(op.getOperation());
@@ -193,7 +193,7 @@ static void transformIndexedGenericOpIndices(
// Offset the index argument `i` by the value of the corresponding induction
// variable and replace all uses of the previous value.
Value newIndex = b.create<AddIOp>(indexedGenericOp.getLoc(), oldIndex,
- pivs[rangeIndex->second]->getValue());
+ ivs[rangeIndex->second]);
for (auto &use : oldIndex.getUses()) {
if (use.getOwner() == newIndex.getDefiningOp())
continue;
@@ -376,15 +376,14 @@ Optional<TiledLinalgOp> static tileLinalgOpImpl(OpBuilder &b, LinalgOp op,
// 3. Create the tiled loops.
LinalgOp res = op;
- auto ivs = ValueHandle::makeIndexHandles(loopRanges.size());
- auto pivs = makeHandlePointers(MutableArrayRef<ValueHandle>(ivs));
+ SmallVector<Value, 4> ivs(loopRanges.size());
// Convert SubViewOp::Range to linalg_range.
SmallVector<Value, 4> linalgRanges;
for (auto &range : loopRanges) {
linalgRanges.push_back(
linalg_range(range.offset, range.size, range.stride));
}
- GenericLoopNestRangeBuilder<LoopTy>(pivs, linalgRanges)([&] {
+ GenericLoopNestRangeBuilder<LoopTy>(ivs, linalgRanges)([&] {
auto b = ScopedContext::getBuilder();
auto loc = ScopedContext::getLocation();
SmallVector<Value, 4> ivValues(ivs.begin(), ivs.end());
@@ -405,7 +404,7 @@ Optional<TiledLinalgOp> static tileLinalgOpImpl(OpBuilder &b, LinalgOp op,
});
// 4. Transforms index arguments of `linalg.generic` w.r.t. to the tiling.
- transformIndexedGenericOpIndices(b, res, pivs, loopIndexToRangeIndex);
+ transformIndexedGenericOpIndices(b, res, ivs, loopIndexToRangeIndex);
// 5. Gather the newly created loops and return them with the new op.
SmallVector<Operation *, 8> loops;
diff --git a/mlir/lib/Dialect/LoopOps/EDSC/Builders.cpp b/mlir/lib/Dialect/LoopOps/EDSC/Builders.cpp
index b7af6635ac5e..7775d8dd0095 100644
--- a/mlir/lib/Dialect/LoopOps/EDSC/Builders.cpp
+++ b/mlir/lib/Dialect/LoopOps/EDSC/Builders.cpp
@@ -14,8 +14,8 @@ using namespace mlir;
using namespace mlir::edsc;
mlir::edsc::ParallelLoopNestBuilder::ParallelLoopNestBuilder(
- ArrayRef<ValueHandle *> ivs, ArrayRef<ValueHandle> lbs,
- ArrayRef<ValueHandle> ubs, ArrayRef<ValueHandle> steps) {
+ MutableArrayRef<Value> ivs, ArrayRef<Value> lbs, ArrayRef<Value> ubs,
+ ArrayRef<Value> steps) {
assert(ivs.size() == lbs.size() && "Mismatch in number of arguments");
assert(ivs.size() == ubs.size() && "Mismatch in number of arguments");
assert(ivs.size() == steps.size() && "Mismatch in number of arguments");
@@ -36,29 +36,34 @@ void mlir::edsc::ParallelLoopNestBuilder::operator()(
(*lit)();
}
-mlir::edsc::LoopNestBuilder::LoopNestBuilder(ArrayRef<ValueHandle *> ivs,
- ArrayRef<ValueHandle> lbs,
- ArrayRef<ValueHandle> ubs,
- ArrayRef<ValueHandle> steps) {
+mlir::edsc::LoopNestBuilder::LoopNestBuilder(MutableArrayRef<Value> ivs,
+ ArrayRef<Value> lbs,
+ ArrayRef<Value> ubs,
+ ArrayRef<Value> steps) {
assert(ivs.size() == lbs.size() && "expected size of ivs and lbs to match");
assert(ivs.size() == ubs.size() && "expected size of ivs and ubs to match");
assert(ivs.size() == steps.size() &&
"expected size of ivs and steps to match");
loops.reserve(ivs.size());
for (auto it : llvm::zip(ivs, lbs, ubs, steps))
- loops.emplace_back(makeLoopBuilder(std::get<0>(it), std::get<1>(it),
+ loops.emplace_back(makeLoopBuilder(&std::get<0>(it), std::get<1>(it),
std::get<2>(it), std::get<3>(it)));
assert(loops.size() == ivs.size() && "Mismatch loops vs ivs size");
}
mlir::edsc::LoopNestBuilder::LoopNestBuilder(
- ValueHandle *iv, ValueHandle lb, ValueHandle ub, ValueHandle step,
- ArrayRef<ValueHandle *> iter_args_handles,
- ValueRange iter_args_init_values) {
- assert(iter_args_init_values.size() == iter_args_handles.size() &&
+ Value *iv, Value lb, Value ub, Value step,
+ MutableArrayRef<Value> iterArgsHandles, ValueRange iterArgsInitValues) {
+ assert(iterArgsInitValues.size() == iterArgsHandles.size() &&
"expected size of arguments and argument_handles to match");
- loops.emplace_back(makeLoopBuilder(iv, lb, ub, step, iter_args_handles,
- iter_args_init_values));
+ loops.emplace_back(
+ makeLoopBuilder(iv, lb, ub, step, iterArgsHandles, iterArgsInitValues));
+}
+
+mlir::edsc::LoopNestBuilder::LoopNestBuilder(Value *iv, Value lb, Value ub,
+ Value step) {
+ SmallVector<Value, 0> noArgs;
+ loops.emplace_back(makeLoopBuilder(iv, lb, ub, step, noArgs, {}));
}
Operation::result_range
@@ -73,10 +78,10 @@ mlir::edsc::LoopNestBuilder::LoopNestBuilder::operator()(
return loops[0].getOp()->getResults();
}
-LoopBuilder mlir::edsc::makeParallelLoopBuilder(ArrayRef<ValueHandle *> ivs,
- ArrayRef<ValueHandle> lbHandles,
- ArrayRef<ValueHandle> ubHandles,
- ArrayRef<ValueHandle> steps) {
+LoopBuilder mlir::edsc::makeParallelLoopBuilder(MutableArrayRef<Value> ivs,
+ ArrayRef<Value> lbHandles,
+ ArrayRef<Value> ubHandles,
+ ArrayRef<Value> steps) {
LoopBuilder result;
auto opHandle = OperationHandle::create<loop::ParallelOp>(
SmallVector<Value, 4>(lbHandles.begin(), lbHandles.end()),
@@ -86,24 +91,22 @@ LoopBuilder mlir::edsc::makeParallelLoopBuilder(ArrayRef<ValueHandle *> ivs,
loop::ParallelOp parallelOp =
cast<loop::ParallelOp>(*opHandle.getOperation());
for (size_t i = 0, e = ivs.size(); i < e; ++i)
- *ivs[i] = ValueHandle(parallelOp.getBody()->getArgument(i));
+ ivs[i] = parallelOp.getBody()->getArgument(i);
result.enter(parallelOp.getBody(), /*prev=*/1);
return result;
}
-mlir::edsc::LoopBuilder
-mlir::edsc::makeLoopBuilder(ValueHandle *iv, ValueHandle lbHandle,
- ValueHandle ubHandle, ValueHandle stepHandle,
- ArrayRef<ValueHandle *> iter_args_handles,
- ValueRange iter_args_init_values) {
+mlir::edsc::LoopBuilder mlir::edsc::makeLoopBuilder(
+ Value *iv, Value lbHandle, Value ubHandle, Value stepHandle,
+ MutableArrayRef<Value> iterArgsHandles, ValueRange iterArgsInitValues) {
mlir::edsc::LoopBuilder result;
auto forOp = OperationHandle::createOp<loop::ForOp>(
- lbHandle, ubHandle, stepHandle, iter_args_init_values);
- *iv = ValueHandle(forOp.getInductionVar());
- auto *body = loop::getForInductionVarOwner(iv->getValue()).getBody();
- for (size_t i = 0, e = iter_args_handles.size(); i < e; ++i) {
+ lbHandle, ubHandle, stepHandle, iterArgsInitValues);
+ *iv = forOp.getInductionVar();
+ auto *body = loop::getForInductionVarOwner(*iv).getBody();
+ for (size_t i = 0, e = iterArgsHandles.size(); i < e; ++i) {
// Skipping the induction variable.
- *(iter_args_handles[i]) = ValueHandle(body->getArgument(i + 1));
+ iterArgsHandles[i] = body->getArgument(i + 1);
}
result.setOp(forOp);
result.enter(body, /*prev=*/1);
diff --git a/mlir/lib/Dialect/StandardOps/EDSC/Builders.cpp b/mlir/lib/Dialect/StandardOps/EDSC/Builders.cpp
index 1232e51341a1..612235d27f9f 100644
--- a/mlir/lib/Dialect/StandardOps/EDSC/Builders.cpp
+++ b/mlir/lib/Dialect/StandardOps/EDSC/Builders.cpp
@@ -14,11 +14,11 @@ using namespace mlir;
using namespace mlir::edsc;
using namespace mlir::edsc::intrinsics;
-static SmallVector<ValueHandle, 8> getMemRefSizes(Value memRef) {
+static SmallVector<Value, 8> getMemRefSizes(Value memRef) {
MemRefType memRefType = memRef.getType().cast<MemRefType>();
assert(isStrided(memRefType) && "Expected strided MemRef type");
- SmallVector<ValueHandle, 8> res;
+ SmallVector<Value, 8> res;
res.reserve(memRefType.getShape().size());
const auto &shape = memRefType.getShape();
for (unsigned idx = 0, n = shape.size(); idx < n; ++idx) {
diff --git a/mlir/lib/Dialect/StandardOps/EDSC/Intrinsics.cpp b/mlir/lib/Dialect/StandardOps/EDSC/Intrinsics.cpp
index f2e2974d76dd..cd8ad74ed4fd 100644
--- a/mlir/lib/Dialect/StandardOps/EDSC/Intrinsics.cpp
+++ b/mlir/lib/Dialect/StandardOps/EDSC/Intrinsics.cpp
@@ -13,45 +13,29 @@ using namespace mlir;
using namespace mlir::edsc;
OperationHandle mlir::edsc::intrinsics::std_br(BlockHandle bh,
- ArrayRef<ValueHandle> operands) {
+ ArrayRef<Value> operands) {
assert(bh && "Expected already captured BlockHandle");
for (auto &o : operands) {
(void)o;
- assert(o && "Expected already captured ValueHandle");
+ assert(o && "Expected already captured Value");
}
SmallVector<Value, 4> ops(operands.begin(), operands.end());
return OperationHandle::create<BranchOp>(bh.getBlock(), ops);
}
-static void enforceEmptyCapturesMatchOperands(ArrayRef<ValueHandle *> captures,
- ArrayRef<ValueHandle> operands) {
- assert(captures.size() == operands.size() &&
- "Expected same number of captures as operands");
- for (auto it : llvm::zip(captures, operands)) {
- (void)it;
- assert(!std::get<0>(it)->hasValue() &&
- "Unexpected already captured ValueHandle");
- assert(std::get<1>(it) && "Expected already captured ValueHandle");
- assert(std::get<0>(it)->getType() == std::get<1>(it).getType() &&
- "Expected the same type for capture and operand");
- }
-}
-
OperationHandle mlir::edsc::intrinsics::std_br(BlockHandle *bh,
- ArrayRef<ValueHandle *> captures,
- ArrayRef<ValueHandle> operands) {
+ ArrayRef<Type> types,
+ MutableArrayRef<Value> captures,
+ ArrayRef<Value> operands) {
assert(!*bh && "Unexpected already captured BlockHandle");
- enforceEmptyCapturesMatchOperands(captures, operands);
- BlockBuilder(bh, captures)(/* no body */);
+ BlockBuilder(bh, types, captures)(/* no body */);
SmallVector<Value, 4> ops(operands.begin(), operands.end());
return OperationHandle::create<BranchOp>(bh->getBlock(), ops);
}
-OperationHandle
-mlir::edsc::intrinsics::std_cond_br(ValueHandle cond, BlockHandle trueBranch,
- ArrayRef<ValueHandle> trueOperands,
- BlockHandle falseBranch,
- ArrayRef<ValueHandle> falseOperands) {
+OperationHandle mlir::edsc::intrinsics::std_cond_br(
+ Value cond, BlockHandle trueBranch, ArrayRef<Value> trueOperands,
+ BlockHandle falseBranch, ArrayRef<Value> falseOperands) {
SmallVector<Value, 4> trueOps(trueOperands.begin(), trueOperands.end());
SmallVector<Value, 4> falseOps(falseOperands.begin(), falseOperands.end());
return OperationHandle::create<CondBranchOp>(
@@ -59,16 +43,14 @@ mlir::edsc::intrinsics::std_cond_br(ValueHandle cond, BlockHandle trueBranch,
}
OperationHandle mlir::edsc::intrinsics::std_cond_br(
- ValueHandle cond, BlockHandle *trueBranch,
- ArrayRef<ValueHandle *> trueCaptures, ArrayRef<ValueHandle> trueOperands,
- BlockHandle *falseBranch, ArrayRef<ValueHandle *> falseCaptures,
- ArrayRef<ValueHandle> falseOperands) {
+ Value cond, BlockHandle *trueBranch, ArrayRef<Type> trueTypes,
+ MutableArrayRef<Value> trueCaptures, ArrayRef<Value> trueOperands,
+ BlockHandle *falseBranch, ArrayRef<Type> falseTypes,
+ MutableArrayRef<Value> falseCaptures, ArrayRef<Value> falseOperands) {
assert(!*trueBranch && "Unexpected already captured BlockHandle");
assert(!*falseBranch && "Unexpected already captured BlockHandle");
- enforceEmptyCapturesMatchOperands(trueCaptures, trueOperands);
- enforceEmptyCapturesMatchOperands(falseCaptures, falseOperands);
- BlockBuilder(trueBranch, trueCaptures)(/* no body */);
- BlockBuilder(falseBranch, falseCaptures)(/* no body */);
+ BlockBuilder(trueBranch, trueTypes, trueCaptures)(/* no body */);
+ BlockBuilder(falseBranch, falseTypes, falseCaptures)(/* no body */);
SmallVector<Value, 4> trueOps(trueOperands.begin(), trueOperands.end());
SmallVector<Value, 4> falseOps(falseOperands.begin(), falseOperands.end());
return OperationHandle::create<CondBranchOp>(
diff --git a/mlir/lib/EDSC/Builders.cpp b/mlir/lib/EDSC/Builders.cpp
index 919990a067e9..247ca4af6c1a 100644
--- a/mlir/lib/EDSC/Builders.cpp
+++ b/mlir/lib/EDSC/Builders.cpp
@@ -65,25 +65,8 @@ MLIRContext *mlir::edsc::ScopedContext::getContext() {
return getBuilder().getContext();
}
-ValueHandle &mlir::edsc::ValueHandle::operator=(const ValueHandle &other) {
- assert(t == other.t && "Wrong type capture");
- assert(!v && "ValueHandle has already been captured, use a new name!");
- v = other.v;
- return *this;
-}
-
-ValueHandle ValueHandle::create(StringRef name, ArrayRef<ValueHandle> operands,
- ArrayRef<Type> resultTypes,
- ArrayRef<NamedAttribute> attributes) {
- Operation *op =
- OperationHandle::create(name, operands, resultTypes, attributes);
- if (op->getNumResults() == 1)
- return ValueHandle(op->getResult(0));
- llvm_unreachable("unsupported operation, use an OperationHandle instead");
-}
-
OperationHandle OperationHandle::create(StringRef name,
- ArrayRef<ValueHandle> operands,
+ ArrayRef<Value> operands,
ArrayRef<Type> resultTypes,
ArrayRef<NamedAttribute> attributes) {
OperationState state(ScopedContext::getLocation(), name);
@@ -156,37 +139,32 @@ mlir::edsc::BlockBuilder::BlockBuilder(BlockHandle bh, Append) {
enter(bh.getBlock());
}
-mlir::edsc::BlockBuilder::BlockBuilder(BlockHandle *bh,
- ArrayRef<ValueHandle *> args) {
+mlir::edsc::BlockBuilder::BlockBuilder(BlockHandle *bh, ArrayRef<Type> types,
+ MutableArrayRef<Value> args) {
assert(!*bh && "BlockHandle already captures a block, use "
"the explicit BockBuilder(bh, Append())({}) syntax instead.");
- SmallVector<Type, 8> types;
- for (auto *a : args) {
- assert(!a->hasValue() &&
- "Expected delayed ValueHandle that has not yet captured.");
- types.push_back(a->getType());
- }
+ assert((args.empty() || args.size() == types.size()) &&
+ "if args captures are specified, their number must match the number "
+ "of types");
*bh = BlockHandle::create(types);
- for (auto it : llvm::zip(args, bh->getBlock()->getArguments())) {
- *(std::get<0>(it)) = ValueHandle(std::get<1>(it));
- }
+ if (!args.empty())
+ for (auto it : llvm::zip(args, bh->getBlock()->getArguments()))
+ std::get<0>(it) = Value(std::get<1>(it));
enter(bh->getBlock());
}
mlir::edsc::BlockBuilder::BlockBuilder(BlockHandle *bh, Region ®ion,
- ArrayRef<ValueHandle *> args) {
+ ArrayRef<Type> types,
+ MutableArrayRef<Value> args) {
assert(!*bh && "BlockHandle already captures a block, use "
"the explicit BockBuilder(bh, Append())({}) syntax instead.");
- SmallVector<Type, 8> types;
- for (auto *a : args) {
- assert(!a->hasValue() &&
- "Expected delayed ValueHandle that has not yet captured.");
- types.push_back(a->getType());
- }
+ assert((args.empty() || args.size() == types.size()) &&
+ "if args captures are specified, their number must match the number "
+ "of types");
*bh = BlockHandle::createInRegion(region, types);
- for (auto it : llvm::zip(args, bh->getBlock()->getArguments())) {
- *(std::get<0>(it)) = ValueHandle(std::get<1>(it));
- }
+ if (!args.empty())
+ for (auto it : llvm::zip(args, bh->getBlock()->getArguments()))
+ std::get<0>(it) = Value(std::get<1>(it));
enter(bh->getBlock());
}
diff --git a/mlir/test/EDSC/builder-api-test.cpp b/mlir/test/EDSC/builder-api-test.cpp
index addf86a99154..75e85ea05722 100644
--- a/mlir/test/EDSC/builder-api-test.cpp
+++ b/mlir/test/EDSC/builder-api-test.cpp
@@ -68,12 +68,11 @@ TEST_FUNC(builder_dynamic_for_func_args) {
OpBuilder builder(f.getBody());
ScopedContext scope(builder, f.getLoc());
- ValueHandle i(indexType), j(indexType), lb(f.getArgument(0)),
- ub(f.getArgument(1));
- ValueHandle f7(std_constant_float(llvm::APFloat(7.0f), f32Type));
- ValueHandle f13(std_constant_float(llvm::APFloat(13.0f), f32Type));
- ValueHandle i7(std_constant_int(7, 32));
- ValueHandle i13(std_constant_int(13, 32));
+ Value i, j, 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));
AffineLoopNestBuilder(&i, lb, ub, 3)([&] {
using namespace edsc::op;
lb *std_constant_index(3) + ub;
@@ -119,8 +118,8 @@ TEST_FUNC(builder_dynamic_for) {
OpBuilder builder(f.getBody());
ScopedContext scope(builder, f.getLoc());
- ValueHandle i(indexType), a(f.getArgument(0)), b(f.getArgument(1)),
- c(f.getArgument(2)), d(f.getArgument(3));
+ Value i, a(f.getArgument(0)), b(f.getArgument(1)), c(f.getArgument(2)),
+ d(f.getArgument(3));
using namespace edsc::op;
AffineLoopNestBuilder(&i, a - b, c + d, 2)();
@@ -141,8 +140,8 @@ TEST_FUNC(builder_loop_for) {
OpBuilder builder(f.getBody());
ScopedContext scope(builder, f.getLoc());
- ValueHandle i(indexType), a(f.getArgument(0)), b(f.getArgument(1)),
- c(f.getArgument(2)), d(f.getArgument(3));
+ Value i, a(f.getArgument(0)), b(f.getArgument(1)), c(f.getArgument(2)),
+ d(f.getArgument(3));
using namespace edsc::op;
LoopNestBuilder(&i, a - b, c + d, a)();
@@ -163,8 +162,8 @@ TEST_FUNC(builder_max_min_for) {
OpBuilder builder(f.getBody());
ScopedContext scope(builder, f.getLoc());
- ValueHandle i(indexType), lb1(f.getArgument(0)), lb2(f.getArgument(1)),
- ub1(f.getArgument(2)), ub2(f.getArgument(3));
+ Value i, lb1(f.getArgument(0)), lb2(f.getArgument(1)), ub1(f.getArgument(2)),
+ ub2(f.getArgument(3));
AffineLoopNestBuilder(&i, {lb1, lb2}, {ub1, ub2}, 1)();
std_ret();
@@ -183,17 +182,20 @@ TEST_FUNC(builder_blocks) {
OpBuilder builder(f.getBody());
ScopedContext scope(builder, f.getLoc());
- ValueHandle c1(ValueHandle::create<ConstantIntOp>(42, 32)),
- c2(ValueHandle::create<ConstantIntOp>(1234, 32));
- ValueHandle arg1(c1.getType()), arg2(c1.getType()), arg3(c1.getType()),
- arg4(c1.getType()), r(c1.getType());
-
+ Value c1(std_constant_int(42, 32)), c2(std_constant_int(1234, 32));
+ Value r;
+ Value args12[2];
+ Value &arg1 = args12[0], &arg2 = args12[1];
+ Value args34[2];
+ Value &arg3 = args34[0], &arg4 = args34[1];
BlockHandle b1, b2, functionBlock(&f.front());
- BlockBuilder(&b1, {&arg1, &arg2})(
+ BlockBuilder(&b1, {c1.getType(), c1.getType()}, args12)(
// b2 has not yet been constructed, need to come back later.
// This is a byproduct of non-structured control-flow.
);
- BlockBuilder(&b2, {&arg3, &arg4})([&] { std_br(b1, {arg3, arg4}); });
+ BlockBuilder(&b2, {c1.getType(), c1.getType()}, args34)([&] {
+ std_br(b1, {arg3, arg4});
+ });
// 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..
@@ -226,24 +228,25 @@ TEST_FUNC(builder_blocks_eager) {
OpBuilder builder(f.getBody());
ScopedContext scope(builder, f.getLoc());
- ValueHandle c1(ValueHandle::create<ConstantIntOp>(42, 32)),
- c2(ValueHandle::create<ConstantIntOp>(1234, 32));
- ValueHandle arg1(c1.getType()), arg2(c1.getType()), arg3(c1.getType()),
- arg4(c1.getType()), r(c1.getType());
+ Value c1(std_constant_int(42, 32)), c2(std_constant_int(1234, 32));
+ Value res;
+ Value args1And2[2], args3And4[2];
+ Value &arg1 = args1And2[0], &arg2 = args1And2[1], &arg3 = args3And4[0],
+ &arg4 = args3And4[1];
// clang-format off
BlockHandle b1, b2;
{ // Toplevel function scope.
// Build a new block for b1 eagerly.
- std_br(&b1, {&arg1, &arg2}, {c1, c2});
+ std_br(&b1, {c1.getType(), c1.getType()}, args1And2, {c1, c2});
// Construct a new block b2 explicitly with a branch into b1.
- BlockBuilder(&b2, {&arg3, &arg4})([&]{
+ BlockBuilder(&b2, {c1.getType(), c1.getType()}, args3And4)([&]{
std_br(b1, {arg3, arg4});
});
/// And come back to append into b1 once b2 exists.
BlockBuilder(b1, Append())([&]{
- r = arg1 + arg2;
- std_br(b2, {arg1, r});
+ res = arg1 + arg2;
+ std_br(b2, {arg1, res});
});
}
@@ -268,15 +271,14 @@ TEST_FUNC(builder_cond_branch) {
OpBuilder builder(f.getBody());
ScopedContext scope(builder, f.getLoc());
- ValueHandle funcArg(f.getArgument(0));
- ValueHandle c32(ValueHandle::create<ConstantIntOp>(32, 32)),
- c64(ValueHandle::create<ConstantIntOp>(64, 64)),
- c42(ValueHandle::create<ConstantIntOp>(42, 32));
- ValueHandle arg1(c32.getType()), arg2(c64.getType()), arg3(c32.getType());
-
+ Value funcArg(f.getArgument(0));
+ Value c32(std_constant_int(32, 32)), c64(std_constant_int(64, 64)),
+ c42(std_constant_int(42, 32));
+ Value arg1;
+ Value args23[2];
BlockHandle b1, b2, functionBlock(&f.front());
- BlockBuilder(&b1, {&arg1})([&] { std_ret(); });
- BlockBuilder(&b2, {&arg2, &arg3})([&] { std_ret(); });
+ BlockBuilder(&b1, c32.getType(), arg1)([&] { std_ret(); });
+ BlockBuilder(&b2, {c64.getType(), c32.getType()}, args23)([&] { std_ret(); });
// Get back to entry block and add a conditional branch
BlockBuilder(functionBlock, Append())([&] {
std_cond_br(funcArg, b1, {c32}, b2, {c64, c42});
@@ -304,15 +306,16 @@ TEST_FUNC(builder_cond_branch_eager) {
OpBuilder builder(f.getBody());
ScopedContext scope(builder, f.getLoc());
- ValueHandle funcArg(f.getArgument(0));
- ValueHandle c32(ValueHandle::create<ConstantIntOp>(32, 32)),
- c64(ValueHandle::create<ConstantIntOp>(64, 64)),
- c42(ValueHandle::create<ConstantIntOp>(42, 32));
- ValueHandle arg1(c32.getType()), arg2(c64.getType()), arg3(c32.getType());
+ Value arg0(f.getArgument(0));
+ Value c32(std_constant_int(32, 32)), c64(std_constant_int(64, 64)),
+ c42(std_constant_int(42, 32));
// clang-format off
BlockHandle b1, b2;
- std_cond_br(funcArg, &b1, {&arg1}, {c32}, &b2, {&arg2, &arg3}, {c64, c42});
+ Value arg1[1], args2And3[2];
+ std_cond_br(arg0,
+ &b1, c32.getType(), arg1, c32,
+ &b2, {c64.getType(), c32.getType()}, args2And3, {c64, c42});
BlockBuilder(b1, Append())([]{
std_ret();
});
@@ -336,7 +339,6 @@ TEST_FUNC(builder_cond_branch_eager) {
TEST_FUNC(builder_helpers) {
using namespace edsc::op;
- auto indexType = IndexType::get(&globalContext());
auto f32Type = FloatType::getF32(&globalContext());
auto memrefType =
MemRefType::get({ShapedType::kDynamicSize, ShapedType::kDynamicSize,
@@ -348,21 +350,20 @@ TEST_FUNC(builder_helpers) {
OpBuilder builder(f.getBody());
ScopedContext scope(builder, f.getLoc());
// clang-format off
- ValueHandle f7(
- ValueHandle::create<ConstantFloatOp>(llvm::APFloat(7.0f), f32Type));
+ 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));
- ValueHandle i(indexType), j(indexType), k1(indexType), k2(indexType),
- lb0(indexType), lb1(indexType), lb2(indexType),
- ub0(indexType), ub1(indexType), ub2(indexType);
+ Value ivs[2];
+ Value &i = ivs[0], &j = ivs[1];
+ Value k1, k2, 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({&i, &j}, {lb0, lb1}, {ub0, ub1}, {step0, step1})([&]{
+ AffineLoopNestBuilder(ivs, {lb0, lb1}, {ub0, ub1}, {step0, step1})([&]{
AffineLoopNestBuilder(&k1, lb2, ub2, step2)([&]{
C(i, j, k1) = f7 + A(i, j, k1) + B(i, j, k1);
});
@@ -393,45 +394,6 @@ TEST_FUNC(builder_helpers) {
f.erase();
}
-TEST_FUNC(custom_ops) {
- using namespace edsc::op;
- auto indexType = IndexType::get(&globalContext());
- auto f = makeFunction("custom_ops", {}, {indexType, indexType});
-
- OpBuilder builder(f.getBody());
- ScopedContext scope(builder, f.getLoc());
- CustomOperation<ValueHandle> MY_CUSTOM_OP("my_custom_op");
- CustomOperation<OperationHandle> MY_CUSTOM_OP_0("my_custom_op_0");
- CustomOperation<OperationHandle> MY_CUSTOM_OP_2("my_custom_op_2");
-
- // clang-format off
- ValueHandle vh(indexType), vh20(indexType), vh21(indexType);
- OperationHandle ih0, ih2;
- ValueHandle m(indexType), n(indexType);
- ValueHandle M(f.getArgument(0)), N(f.getArgument(1));
- ValueHandle ten(std_constant_index(10)), twenty(std_constant_index(20));
- AffineLoopNestBuilder({&m, &n}, {M, N}, {M + ten, N + twenty}, {1, 1})([&]{
- vh = MY_CUSTOM_OP({m, m + n}, {indexType}, {});
- ih0 = MY_CUSTOM_OP_0({m, m + n}, {});
- ih2 = MY_CUSTOM_OP_2({m, m + n}, {indexType, indexType});
- // These captures are verbose for now, can improve when used in practice.
- vh20 = ValueHandle(ih2.getOperation()->getResult(0));
- vh21 = ValueHandle(ih2.getOperation()->getResult(1));
- MY_CUSTOM_OP({vh20, vh21}, {indexType}, {});
- });
-
- // CHECK-LABEL: @custom_ops
- // CHECK: affine.for %{{.*}} {{.*}}
- // CHECK: affine.for %{{.*}} {{.*}}
- // CHECK: {{.*}} = "my_custom_op"{{.*}} : (index, index) -> index
- // CHECK: "my_custom_op_0"{{.*}} : (index, index) -> ()
- // CHECK: [[TWO:%[a-z0-9]+]]:2 = "my_custom_op_2"{{.*}} : (index, index) -> (index, index)
- // CHECK: {{.*}} = "my_custom_op"([[TWO]]#0, [[TWO]]#1) : (index, index) -> index
- // clang-format on
- f.print(llvm::outs());
- f.erase();
-}
-
TEST_FUNC(insertion_in_block) {
using namespace edsc::op;
auto indexType = IndexType::get(&globalContext());
@@ -441,11 +403,11 @@ TEST_FUNC(insertion_in_block) {
ScopedContext scope(builder, f.getLoc());
BlockHandle b1;
// clang-format off
- ValueHandle::create<ConstantIntOp>(0, 32);
- BlockBuilder(&b1, {})([]{
- ValueHandle::create<ConstantIntOp>(1, 32);
+ std_constant_int(0, 32);
+ (BlockBuilder(&b1))([]{
+ std_constant_int(1, 32);
});
- ValueHandle::create<ConstantIntOp>(2, 32);
+ std_constant_int(2, 32);
// CHECK-LABEL: @insertion_in_block
// CHECK: {{.*}} = constant 0 : i32
// CHECK: {{.*}} = constant 2 : i32
@@ -469,8 +431,8 @@ TEST_FUNC(zero_and_std_sign_extendi_op_i1_to_i8) {
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);
+ 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
@@ -489,8 +451,8 @@ TEST_FUNC(operator_or) {
ScopedContext scope(builder, f.getLoc());
using op::operator||;
- ValueHandle lhs(f.getArgument(0));
- ValueHandle rhs(f.getArgument(1));
+ Value lhs(f.getArgument(0));
+ Value rhs(f.getArgument(1));
lhs || rhs;
// CHECK-LABEL: @operator_or
@@ -508,8 +470,8 @@ TEST_FUNC(operator_and) {
ScopedContext scope(builder, f.getLoc());
using op::operator&&;
- ValueHandle lhs(f.getArgument(0));
- ValueHandle rhs(f.getArgument(1));
+ Value lhs(f.getArgument(0));
+ Value rhs(f.getArgument(1));
lhs &&rhs;
// CHECK-LABEL: @operator_and
@@ -521,7 +483,6 @@ TEST_FUNC(operator_and) {
TEST_FUNC(select_op_i32) {
using namespace edsc::op;
- auto indexType = IndexType::get(&globalContext());
auto f32Type = FloatType::getF32(&globalContext());
auto memrefType = MemRefType::get(
{ShapedType::kDynamicSize, ShapedType::kDynamicSize}, f32Type, {}, 0);
@@ -530,17 +491,13 @@ TEST_FUNC(select_op_i32) {
OpBuilder builder(f.getBody());
ScopedContext scope(builder, f.getLoc());
// clang-format off
- ValueHandle zero = std_constant_index(0), one = std_constant_index(1);
+ Value zero = std_constant_index(0), one = std_constant_index(1);
MemRefBoundsCapture vA(f.getArgument(0));
AffineIndexedValue A(f.getArgument(0));
- ValueHandle i(indexType), j(indexType);
- AffineLoopNestBuilder({&i, &j}, {zero, zero}, {one, one}, {1, 1})([&]{
- // This test exercises AffineIndexedValue::operator Value.
- // Without it, one must force conversion to ValueHandle as such:
- // std_select(
- // i == zero, ValueHandle(A(zero, zero)), ValueHandle(ValueA(i, j)))
- using edsc::op::operator==;
- std_select(i == zero, *A(zero, zero), *A(i, j));
+ Value ivs[2];
+ Value &i = ivs[0], &j = ivs[1];
+ AffineLoopNestBuilder(ivs, {zero, zero}, {one, one}, {1, 1})([&]{
+ std_select(eq(i, zero), A(zero, zero), A(i, j));
});
// CHECK-LABEL: @select_op
@@ -556,7 +513,6 @@ TEST_FUNC(select_op_i32) {
}
TEST_FUNC(select_op_f32) {
- auto indexType = IndexType::get(&globalContext());
auto f32Type = FloatType::getF32(&globalContext());
auto memrefType = MemRefType::get(
{ShapedType::kDynamicSize, ShapedType::kDynamicSize}, f32Type, {}, 0);
@@ -565,18 +521,19 @@ TEST_FUNC(select_op_f32) {
OpBuilder builder(f.getBody());
ScopedContext scope(builder, f.getLoc());
// clang-format off
- ValueHandle zero = std_constant_index(0), one = std_constant_index(1);
+ 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));
- ValueHandle i(indexType), j(indexType);
- AffineLoopNestBuilder({&i, &j}, {zero, zero}, {one, one}, {1, 1})([&]{
+ Value ivs[2];
+ Value &i = ivs[0], &j = ivs[1];
+ AffineLoopNestBuilder(ivs, {zero, zero}, {one, one}, {1, 1})([&]{
using namespace edsc::op;
- std_select(B(i, j) == B(i + one, j), *A(zero, zero), *A(i, j));
- std_select(B(i, j) != B(i + one, j), *A(zero, zero), *A(i, j));
- std_select(B(i, j) >= B(i + one, j), *A(zero, zero), *A(i, j));
- std_select(B(i, j) <= B(i + one, j), *A(zero, zero), *A(i, j));
- std_select(B(i, j) < B(i + one, j), *A(zero, zero), *A(i, j));
- std_select(B(i, j) > B(i + one, j), *A(zero, zero), *A(i, j));
+ 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(B(i, j) >= B(i + one, j), A(zero, zero), A(i, j));
+ std_select(B(i, j) <= B(i + one, j), A(zero, zero), A(i, j));
+ std_select(B(i, j) < B(i + one, j), A(zero, zero), A(i, j));
+ std_select(B(i, j) > B(i + one, j), A(zero, zero), A(i, j));
});
// CHECK-LABEL: @select_op
@@ -632,7 +589,6 @@ TEST_FUNC(select_op_f32) {
// Inject an EDSC-constructed computation to exercise imperfectly nested 2-d
// tiling.
TEST_FUNC(tile_2d) {
- auto indexType = IndexType::get(&globalContext());
auto memrefType =
MemRefType::get({ShapedType::kDynamicSize, ShapedType::kDynamicSize,
ShapedType::kDynamicSize},
@@ -641,17 +597,19 @@ TEST_FUNC(tile_2d) {
OpBuilder builder(f.getBody());
ScopedContext scope(builder, f.getLoc());
- ValueHandle zero = std_constant_index(0);
+ 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));
- ValueHandle i(indexType), j(indexType), k1(indexType), k2(indexType);
- ValueHandle M(vC.ub(0)), N(vC.ub(1)), O(vC.ub(2));
+ Value ivs[2];
+ Value &i = ivs[0], &j = ivs[1];
+ Value k1, k2;
+ Value M(vC.ub(0)), N(vC.ub(1)), O(vC.ub(2));
// clang-format off
using namespace edsc::op;
- AffineLoopNestBuilder({&i, &j}, {zero, zero}, {M, N}, {1, 1})([&]{
+ AffineLoopNestBuilder(ivs, {zero, zero}, {M, N}, {1, 1})([&]{
AffineLoopNestBuilder(&k1, zero, O, 1)([&]{
C(i, j, k1) = A(i, j, k1) + B(i, j, k1);
});
@@ -661,10 +619,8 @@ TEST_FUNC(tile_2d) {
});
// clang-format on
- auto li = getForInductionVarOwner(i.getValue()),
- lj = getForInductionVarOwner(j.getValue()),
- lk1 = getForInductionVarOwner(k1.getValue()),
- lk2 = getForInductionVarOwner(k2.getValue());
+ 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);
@@ -713,15 +669,15 @@ TEST_FUNC(indirect_access) {
OpBuilder builder(f.getBody());
ScopedContext scope(builder, f.getLoc());
- ValueHandle zero = std_constant_index(0);
+ Value zero = std_constant_index(0);
MemRefBoundsCapture vC(f.getArgument(2));
AffineIndexedValue B(f.getArgument(1)), D(f.getArgument(3));
StdIndexedValue A(f.getArgument(0)), C(f.getArgument(2));
- ValueHandle i(builder.getIndexType()), N(vC.ub(0));
+ Value i, N(vC.ub(0));
// clang-format off
AffineLoopNestBuilder(&i, zero, N, 1)([&]{
- C((ValueHandle)D(i)) = A((ValueHandle)B(i));
+ C((Value)D(i)) = A((Value)B(i));
});
// clang-format on
@@ -747,12 +703,12 @@ TEST_FUNC(empty_map_load_store) {
OpBuilder builder(f.getBody());
ScopedContext scope(builder, f.getLoc());
- ValueHandle zero = std_constant_index(0);
- ValueHandle one = std_constant_index(1);
+ Value zero = std_constant_index(0);
+ Value one = std_constant_index(1);
AffineIndexedValue input(f.getArgument(0)), res(f.getArgument(1));
- ValueHandle iv(builder.getIndexType());
// clang-format off
+ Value iv;
AffineLoopNestBuilder(&iv, zero, one, 1)([&]{
res() = input();
});
@@ -784,7 +740,7 @@ TEST_FUNC(affine_if_op) {
OpBuilder builder(f.getBody());
ScopedContext scope(builder, f.getLoc());
- ValueHandle zero = std_constant_index(0), ten = std_constant_index(10);
+ Value zero = std_constant_index(0), ten = std_constant_index(10);
SmallVector<bool, 4> isEq = {false, false, false, false};
SmallVector<AffineExpr, 4> affineExprs = {
@@ -834,7 +790,7 @@ TEST_FUNC(linalg_generic_pointwise_test) {
OpBuilder builder(f.getBody());
ScopedContext scope(builder, f.getLoc());
- ValueHandle A(f.getArgument(0)), B(f.getArgument(1)), C(f.getArgument(2));
+ 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);
@@ -864,12 +820,12 @@ TEST_FUNC(linalg_generic_matmul_test) {
auto f32Type = FloatType::getF32(&globalContext());
auto memrefType = MemRefType::get(
{ShapedType::kDynamicSize, ShapedType::kDynamicSize}, f32Type, {}, 0);
- auto f =
- makeFunction("linalg_generic_matmul", {}, {memrefType, memrefType, memrefType});
+ auto f = makeFunction("linalg_generic_matmul", {},
+ {memrefType, memrefType, memrefType});
OpBuilder builder(f.getBody());
ScopedContext scope(builder, f.getLoc());
- linalg_generic_matmul(makeValueHandles(llvm::to_vector<3>(f.getArguments())));
+ linalg_generic_matmul(f.getArguments());
f.print(llvm::outs());
f.erase();
@@ -902,8 +858,8 @@ TEST_FUNC(linalg_generic_conv_nhwc) {
OpBuilder builder(f.getBody());
ScopedContext scope(builder, f.getLoc());
- linalg_generic_conv_nhwc(makeValueHandles(llvm::to_vector<3>(f.getArguments())),
- /*strides=*/{3, 4}, /*dilations=*/{5, 6});
+ linalg_generic_conv_nhwc(f.getArguments(),
+ /*strides=*/{3, 4}, /*dilations=*/{5, 6});
f.print(llvm::outs());
f.erase();
@@ -936,9 +892,9 @@ TEST_FUNC(linalg_generic_dilated_conv_nhwc) {
OpBuilder builder(f.getBody());
ScopedContext scope(builder, f.getLoc());
- linalg_generic_dilated_conv_nhwc(makeValueHandles(f.getArguments()),
- /*depth_multiplier=*/7,
- /*strides=*/{3, 4}, /*dilations=*/{5, 6});
+ linalg_generic_dilated_conv_nhwc(f.getArguments(),
+ /*depth_multiplier=*/7,
+ /*strides=*/{3, 4}, /*dilations=*/{5, 6});
f.print(llvm::outs());
f.erase();
@@ -958,7 +914,7 @@ TEST_FUNC(linalg_metadata_ops) {
ScopedContext scope(builder, f.getLoc());
AffineExpr i, j, k;
bindDims(&globalContext(), i, j, k);
- ValueHandle v(f.getArgument(0));
+ Value v(f.getArgument(0));
auto reshaped = linalg_reshape(v, ArrayRef<ArrayRef<AffineExpr>>{{i, j}, k});
linalg_reshape(memrefType, reshaped,
ArrayRef<ArrayRef<AffineExpr>>{{i, j}, k});
@@ -1015,7 +971,7 @@ TEST_FUNC(linalg_tensors_test) {
OpBuilder builder(f.getBody());
ScopedContext scope(builder, f.getLoc());
- ValueHandle A(f.getArgument(0)), B(f.getArgument(1));
+ Value A(f.getArgument(0)), B(f.getArgument(1));
AffineExpr i, j;
bindDims(&globalContext(), i, j);
StructuredIndexed SA(A), SB(B), SC(tensorType);
@@ -1023,7 +979,7 @@ TEST_FUNC(linalg_tensors_test) {
linalg_generic_pointwise_max(SA({i, j}), SB({i, j}), SC({i, j}));
linalg_generic_pointwise_tanh(SA({i, j}), SC({i, j}));
Value o1 = linalg_generic_matmul(A, B, tensorType)->getResult(0);
- linalg_generic_matmul(A, B, ValueHandle(o1), tensorType);
+ linalg_generic_matmul(A, B, o1, tensorType);
f.print(llvm::outs());
f.erase();
@@ -1064,7 +1020,7 @@ TEST_FUNC(memref_vector_matmul_test) {
OpBuilder builder(f.getBody());
ScopedContext scope(builder, f.getLoc());
- ValueHandle A(f.getArgument(0)), B(f.getArgument(1)), C(f.getArgument(2));
+ Value A(f.getArgument(0)), B(f.getArgument(1)), C(f.getArgument(2));
auto contractionBuilder = [](ArrayRef<BlockArgument> args) {
assert(args.size() == 3 && "expected 3 block arguments");
(linalg_yield(vector_contraction_matmul(args[0], args[1], args[2])));
@@ -1083,19 +1039,19 @@ TEST_FUNC(builder_loop_for_yield) {
OpBuilder builder(f.getBody());
ScopedContext scope(builder, f.getLoc());
- ValueHandle init0 = std_constant_float(llvm::APFloat(1.0f), f32Type);
- ValueHandle init1 = std_constant_float(llvm::APFloat(2.0f), f32Type);
- ValueHandle i(indexType), a(f.getArgument(0)), b(f.getArgument(1)),
- c(f.getArgument(2)), d(f.getArgument(3));
- ValueHandle arg0(f32Type);
- ValueHandle arg1(f32Type);
+ Value init0 = std_constant_float(llvm::APFloat(1.0f), f32Type);
+ Value init1 = std_constant_float(llvm::APFloat(2.0f), f32Type);
+ Value i, a(f.getArgument(0)), b(f.getArgument(1)), c(f.getArgument(2)),
+ d(f.getArgument(3));
+ Value args01[2];
+ Value &arg0 = args01[0], &arg1 = args01[1];
using namespace edsc::op;
auto results =
- LoopNestBuilder(&i, a - b, c + d, a, {&arg0, &arg1}, {init0, init1})([&] {
+ LoopNestBuilder(&i, a - b, c + d, a, args01, {init0, init1})([&] {
auto sum = arg0 + arg1;
- loop_yield(ArrayRef<ValueHandle>{arg1, sum});
+ loop_yield(ArrayRef<Value>{arg1, sum});
});
- ValueHandle(results[0]) + ValueHandle(results[1]);
+ results[0] + results[1];
// clang-format off
// CHECK-LABEL: func @builder_loop_for_yield(%{{.*}}: index, %{{.*}}: index, %{{.*}}: index, %{{.*}}: index) {
diff --git a/mlir/test/mlir-linalg-ods-gen/test-linalg-ods-gen.tc b/mlir/test/mlir-linalg-ods-gen/test-linalg-ods-gen.tc
index 2e7166d60a6b..0b88f2aa11a2 100644
--- a/mlir/test/mlir-linalg-ods-gen/test-linalg-ods-gen.tc
+++ b/mlir/test/mlir-linalg-ods-gen/test-linalg-ods-gen.tc
@@ -16,9 +16,9 @@
// IMPL-NEXT: AffineMap::get(2, 0, {d0}, context) };
//
// IMPL: Test1Op::regionBuilder(Block &block) {
-// IMPL: ValueHandle [[a:.*]](args[0]), [[b:.*]](args[1]), [[c:.*]](args[2]);
-// IMPL: ValueHandle [[d:.*]] = std_mulf([[a]], [[b]]);
-// IMPL: ValueHandle [[e:.*]] = std_addf([[c]], [[d]]);
+// IMPL: Value [[a:.*]](args[0]), [[b:.*]](args[1]), [[c:.*]](args[2]);
+// IMPL: Value [[d:.*]] = std_mulf([[a]], [[b]]);
+// IMPL: Value [[e:.*]] = std_addf([[c]], [[d]]);
// IMPL: (linalg_yield(ValueRange{ [[e]] }));
//
ods_def<Test1Op> :
@@ -41,9 +41,9 @@ def test1(A: f32(M, K), B: f32(K)) -> (C: f32(M)) {
// IMPL-NEXT: AffineMap::get(3, 0, {d0, d1}, context) };
//
// IMPL: Test2Op::regionBuilder(Block &block) {
-// IMPL: ValueHandle [[a:.*]](args[0]), [[b:.*]](args[1]), [[c:.*]](args[2]);
-// IMPL: ValueHandle [[d:.*]] = std_mulf([[a]], [[b]]);
-// IMPL: ValueHandle [[e:.*]] = std_addf([[c]], [[d]]);
+// IMPL: Value [[a:.*]](args[0]), [[b:.*]](args[1]), [[c:.*]](args[2]);
+// IMPL: Value [[d:.*]] = std_mulf([[a]], [[b]]);
+// IMPL: Value [[e:.*]] = std_addf([[c]], [[d]]);
// IMPL: (linalg_yield(ValueRange{ [[e]] }));
//
ods_def<Test2Op> :
@@ -66,9 +66,9 @@ def test2(A: f32(M, K), B: f32(K, N)) -> (C: f32(M, N)) {
// IMPL-NEXT: AffineMap::get(4, 0, {d0, d1, d2}, context) };
//
// IMPL: Test3Op::regionBuilder(Block &block) {
-// IMPL: ValueHandle [[a:.*]](args[0]), [[b:.*]](args[1]), [[c:.*]](args[2]);
-// IMPL: ValueHandle [[d:.*]] = std_mulf([[a]], [[b]]);
-// IMPL: ValueHandle [[e:.*]] = std_addf([[c]], [[d]]);
+// IMPL: Value [[a:.*]](args[0]), [[b:.*]](args[1]), [[c:.*]](args[2]);
+// IMPL: Value [[d:.*]] = std_mulf([[a]], [[b]]);
+// IMPL: Value [[e:.*]] = std_addf([[c]], [[d]]);
// IMPL: (linalg_yield(ValueRange{ [[e]] }));
//
ods_def<Test3Op> :
diff --git a/mlir/tools/mlir-linalg-ods-gen/mlir-linalg-ods-gen.cpp b/mlir/tools/mlir-linalg-ods-gen/mlir-linalg-ods-gen.cpp
index 1132806da175..c1395f7655ed 100644
--- a/mlir/tools/mlir-linalg-ods-gen/mlir-linalg-ods-gen.cpp
+++ b/mlir/tools/mlir-linalg-ods-gen/mlir-linalg-ods-gen.cpp
@@ -1601,7 +1601,7 @@ void TCParser::printRegionBuilder(llvm::raw_ostream &os, StringRef cppOpName,
printExpr(subExprsStringStream, *e);
});
subExprsStringStream.flush();
- const char *tensorExprFmt = "\n ValueHandle _{0} = {1}({2});";
+ const char *tensorExprFmt = "\n Value _{0} = {1}({2});";
os << llvm::formatv(tensorExprFmt, ++count, pTensorExpr->operationName,
subExprs);
subExprsMap[pTensorExpr] = count;
@@ -1613,7 +1613,7 @@ void TCParser::printRegionBuilder(llvm::raw_ostream &os, StringRef cppOpName,
using namespace edsc;
using namespace intrinsics;
auto args = block.getArguments();
- ValueHandle {1};
+ Value {1};
{2}
(linalg_yield(ValueRange{ {3} }));
})FMT";
More information about the Mlir-commits
mailing list