return success();
}
+ // Inject an EDSC-constructed computation that assigns Stmt and uses the LHS.
+ if (f->getName().strref().contains("assignments")) {
+ FuncBuilder builder(f);
+ edsc::ScopedEDSCContext context;
+ edsc::MLIREmitter emitter(&builder, f->getLoc());
+
+ edsc::Expr zero = emitter.zero();
+ edsc::Expr one = emitter.one();
+ auto args = emitter.makeBoundFunctionArguments(f);
+ auto views = emitter.makeBoundMemRefViews(args.begin(), args.end());
+
+ Type indexType = builder.getIndexType();
+ edsc::Expr i(indexType);
+ edsc::Expr A = args[0], B = args[1], C = args[2];
+ edsc::Expr M = views[0].dim(0);
+ // clang-format off
+ using namespace edsc::op;
+ edsc::Stmt scalarA, scalarB, tmp;
+ auto block = edsc::block({
+ For(i, zero, M, one, {
+ scalarA = load(A, {i}),
+ scalarB = load(B, {i}),
+ tmp = scalarA * scalarB,
+ store(tmp, C, {i})
+ }),
+ });
+ // clang-format on
+
+ emitter.emitStmts(block.getBody());
+ }
+
f->walk([](Instruction *op) {
if (op->getName().getStringRef() == "print") {
auto opName = op->getAttrOfType<StringAttr>("op");
auto *lbDef = lb->getDefiningInst();
(void)lbDef;
assert((!lbDef || lbDef->isa<ConstantIndexOp>() ||
- lbDef->isa<AffineApplyOp>() || lbDef->isa<AffineForOp>()) &&
+ lbDef->isa<AffineApplyOp>() || lbDef->isa<AffineForOp>() ||
+ lbDef->isa<DimOp>()) &&
"lower bound expression does not have affine provenance");
auto *ubDef = ub->getDefiningInst();
(void)ubDef;
assert((!ubDef || ubDef->isa<ConstantIndexOp>() ||
- ubDef->isa<AffineApplyOp>() || ubDef->isa<AffineForOp>()) &&
+ ubDef->isa<AffineApplyOp>() || ubDef->isa<AffineForOp>() ||
+ ubDef->isa<DimOp>()) &&
"upper bound expression does not have affine provenance");
// Step must be a static constant.
}
Stmt &mlir::edsc::Stmt::operator=(const Expr &expr) {
- Stmt res(Bindable(Expr(Type())), expr, {});
+ auto types = expr.getResultTypes();
+ assert(types.size() == 1 && "single result Expr expected in Stmt::operator=");
+ Stmt res(Bindable(Expr(types.front())), expr, {});
std::swap(res.storage, this->storage);
return *this;
}
func @dynamic_for(%arg0 : index, %arg1 : index, %arg2 : index, %arg3 : index) {
return
}
+
+// These functions will be detected by the test pass that will insert an
+// EDSC-constructed 1-D pointwise-add loop with assignments to scalars before
+// the `return` instruction.
+//
+// CHECK-LABEL: func @assignments_1(%arg0: memref<4xf32>, %arg1: memref<4xf32>, %arg2: memref<4xf32>) {
+// CHECK: for %[[iv:.*]] = 0 to 4 {
+// CHECK: %[[a:.*]] = load %arg0[%[[iv]]] : memref<4xf32>
+// CHECK: %[[b:.*]] = load %arg1[%[[iv]]] : memref<4xf32>
+// CHECK: %[[tmp:.*]] = mulf %[[a]], %[[b]] : f32
+// CHECK: store %[[tmp]], %arg2[%[[iv]]] : memref<4xf32>
+func @assignments_1(%arg0: memref<4xf32>, %arg1: memref<4xf32>, %arg2: memref<4xf32>) {
+ return
+}
+
+// CHECK-LABEL: func @assignments_2(%arg0: memref<?xf32>, %arg1: memref<?xf32>, %arg2: memref<?xf32>) {
+// CHECK: for %[[iv:.*]] = {{.*}} to {{.*}} {
+// CHECK: %[[a:.*]] = load %arg0[%[[iv]]] : memref<?xf32>
+// CHECK: %[[b:.*]] = load %arg1[%[[iv]]] : memref<?xf32>
+// CHECK: %[[tmp:.*]] = mulf %[[a]], %[[b]] : f32
+// CHECK: store %[[tmp]], %arg2[%[[iv]]] : memref<?xf32>
+func @assignments_2(%arg0: memref<?xf32>, %arg1: memref<?xf32>, %arg2: memref<?xf32>) {
+ return
+}