From 61de73b428b145f531d3cbd25fec9f6eb9530bc8 Mon Sep 17 00:00:00 2001
From: tqchen <tianqi.tchen@gmail.com>
Date: Sun, 27 Nov 2016 23:21:57 -0800
Subject: [PATCH] Finalize tensor and operation

---
 include/tvm/ir_pass.h       |  9 ++++
 include/tvm/operation.h     | 76 ++++++++++++++++------------
 include/tvm/tensor.h        | 99 +++++++++++++++++--------------------
 src/lang/operation.cc       | 42 +++++++++++++---
 src/pass/schedule_ops.cc    | 24 +++++++++
 tests/python/test_tensor.py |  4 +-
 6 files changed, 159 insertions(+), 95 deletions(-)
 create mode 100644 src/pass/schedule_ops.cc

diff --git a/include/tvm/ir_pass.h b/include/tvm/ir_pass.h
index def17377d..c887c4b88 100644
--- a/include/tvm/ir_pass.h
+++ b/include/tvm/ir_pass.h
@@ -13,6 +13,7 @@
 #include <unordered_map>
 #include <vector>
 #include "./expr.h"
+#include "./schedule.h"
 
 namespace tvm {
 namespace ir {
@@ -50,6 +51,14 @@ Stmt Inline(FunctionRef f,
             Expr body,
             Stmt stmt);
 
+/*!
+ * \brief Schedule s' dependent operations.
+ *
+ * \param s The schedule to be realized
+ * \return the result Stmt
+ */
+Stmt ScheduelOps(Schedule s);
+
 }  // namespace ir
 }  // namespace tvm
 
diff --git a/include/tvm/operation.h b/include/tvm/operation.h
index 5906f578e..8bf72ab54 100644
--- a/include/tvm/operation.h
+++ b/include/tvm/operation.h
@@ -9,43 +9,15 @@
 #include <string>
 #include "./expr.h"
 #include "./domain.h"
+#include "./tensor.h"
 
 namespace tvm {
 
-// internal node container for Operation
-class OperationNode;
-
-/*! \brief Split over input domain */
-class Operation : public NodeRef {
- public:
-  /*! \brief default constructor  */
-  Operation() {}
-  explicit Operation(std::shared_ptr<Node> n) : NodeRef(n) {}
-  /*!
-   * \brief access the internal node container
-   * \return the pointer to the internal node container
-   */
-  inline const OperationNode* operator->() const;
-};
-
-/*!
- * \brief base class of operation node.
- */
-class OperationNode : public Node {
- public:
-  /*! \brief The domain of iteration of this op. */
-  Domain domain;
-  /*! \brief optional name of the operation */
-  std::string name;
-};
-
 /*!
  * \brief A Compute op that compute a tensor on certain domain.
  */
 class ComputeOpNode : public OperationNode {
  public:
-  /*! \brief iter-Var over the dimensions */
-  Array<Var> dim_var;
   /*! \brief the compute expression */
   Expr body;
   /*! \brief constructor */
@@ -54,6 +26,12 @@ class ComputeOpNode : public OperationNode {
   const char* type_key() const final {
     return "ComputeOp";
   }
+  size_t num_outputs() const final {
+    return 1;
+  }
+  std::string output_name(size_t i) const final;
+  Type output_dtype(size_t i) const final;
+  Array<Expr> output_shape(size_t i) const final;
   void VisitAttrs(AttrVisitor* v) final {
     v->Visit("domain", &domain);
     v->Visit("name", &name);
@@ -66,9 +44,43 @@ class ComputeOpNode : public OperationNode {
                         Expr body);
 };
 
-// Implementations of inline functions
-inline const OperationNode* Operation::operator->() const {
-  return static_cast<const OperationNode*>(node_.get());
+
+/*! \brief The compute function to specify the input source of a Tensor */
+using FCompute = std::function<Expr (const Array<Var>& i)>;
+
+/*!
+ * \brief Construct a new tensor by computing over shape,
+ *  using the computation rule: result_tensor[axis] = fcompute(axis)
+ * \param shape Shape of the tensor.
+ * \param fcompute The compute function to create the tensor.
+ * \param name The optional name of the tensor.
+ */
+Tensor Compute(Array<Expr> shape, FCompute fcompute, std::string name = "tensor");
+
+// same as compute, specialized for different fcompute function
+inline Tensor Compute(Array<Expr> shape,
+                      std::function<Expr(Var)> f,
+                      std::string name = "tensor") {
+  FCompute fc = [f] (const Array<Var>& i) { return f(i[0]); };
+  return Compute(shape, fc, name);
+}
+inline Tensor Compute(Array<Expr> shape,
+                      std::function<Expr(Var, Var)> f,
+                      std::string name = "tensor") {
+  FCompute fc = [f] (const Array<Var>& i) { return f(i[0], i[1]); };
+  return Compute(shape, fc, name);
+}
+inline Tensor Compute(Array<Expr> shape,
+                      std::function<Expr(Var, Var, Var)> f,
+                      std::string name = "tensor") {
+  FCompute fc = [f] (const Array<Var>& i) { return f(i[0], i[1], i[2]); };
+  return  Compute(shape, fc, name);
+}
+inline Tensor Compute(Array<Expr> shape,
+                      std::function<Expr(Var, Var, Var, Var)> f,
+                      std::string name = "tensor") {
+  FCompute fc = [f] (const Array<Var>& i) { return f(i[0], i[1], i[2], i[3]); };
+  return Compute(shape, fc, name);
 }
 
 }  // namespace tvm
diff --git a/include/tvm/tensor.h b/include/tvm/tensor.h
index e293c0de7..ce3d9db23 100644
--- a/include/tvm/tensor.h
+++ b/include/tvm/tensor.h
@@ -14,12 +14,14 @@
 
 #include "./base.h"
 #include "./expr.h"
-#include "./operation.h"
+#include "./domain.h"
 
 namespace tvm {
 
 // Internal node container of Tensor
 class TensorNode;
+// internal node container for Operation
+class OperationNode;
 
 using Halide::IR::FunctionRef;
 
@@ -68,57 +70,24 @@ class Tensor : public FunctionRef {
   friend std::ostream& operator<<(std::ostream &os, const Tensor& t);
 };
 
-/*! \brief The compute function to specify the input source of a Tensor */
-using FCompute = std::function<Expr (const Array<Var>& i)>;
-
-// converters from other functions into fcompute
-inline FCompute GetFCompute(std::function<Expr(Var x)> f) {
-  return [f] (const Array<Var>& i) { return f(i[0]); };
-}
-inline FCompute GetFCompute(std::function<Expr(Var, Var)> f) {
-  return [f] (const Array<Var>& i) { return f(i[0], i[1]); };
-}
-inline FCompute GetFCompute(std::function<Expr(Var, Var, Var)> f) {
-  return [f] (const Array<Var>& i) { return f(i[0], i[1], i[2]); };
-}
-inline FCompute GetFCompute(std::function<Expr(Var, Var, Var, Var)> f) {
-  return [f] (const Array<Var>& i) { return f(i[0], i[1], i[2], i[3]); };
-}
-
-/*!
- * \brief Construct a new tensor by computing over shape,
- *  using the computation rule: result_tensor[axis] = fcompute(axis)
- * \param shape Shape of the tensor.
- * \param fcompute The compute function to create the tensor.
- * \param name The optional name of the tensor.
- */
-Tensor Compute(Array<Expr> shape, FCompute fcompute, std::string name = "tensor");
-
-// same as compute, specialized for different fcompute function
-inline Tensor Compute(Array<Expr> shape,
-                      std::function<Expr(Var)> f,
-                      std::string name = "tensor") {
-  FCompute fc = [f] (const Array<Var>& i) { return f(i[0]); };
-  return Compute(shape, fc, name);
-}
-inline Tensor Compute(Array<Expr> shape,
-                      std::function<Expr(Var, Var)> f,
-                      std::string name = "tensor") {
-  FCompute fc = [f] (const Array<Var>& i) { return f(i[0], i[1]); };
-  return Compute(shape, fc, name);
-}
-inline Tensor Compute(Array<Expr> shape,
-                      std::function<Expr(Var, Var, Var)> f,
-                      std::string name = "tensor") {
-  FCompute fc = [f] (const Array<Var>& i) { return f(i[0], i[1], i[2]); };
-  return  Compute(shape, fc, name);
-}
-inline Tensor Compute(Array<Expr> shape,
-                      std::function<Expr(Var, Var, Var, Var)> f,
-                      std::string name = "tensor") {
-  FCompute fc = [f] (const Array<Var>& i) { return f(i[0], i[1], i[2], i[3]); };
-  return Compute(shape, fc, name);
-}
+/*! \brief Operation that produces tensors */
+class Operation : public NodeRef {
+ public:
+  /*! \brief default constructor  */
+  Operation() {}
+  explicit Operation(std::shared_ptr<Node> n) : NodeRef(n) {}
+  /*!
+   * \brief access the internal node container
+   * \return the pointer to the internal node container
+   */
+  inline const OperationNode* operator->() const;
+  /*!
+   * \brief get the i-th output of the operation.
+   * \param i the output index.
+   * \return The i-th output.
+   */
+  Tensor output(size_t i) const;
+};
 
 /*! \brief Node to represent a tensor */
 class TensorNode : public FunctionBaseNode {
@@ -158,7 +127,31 @@ class TensorNode : public FunctionBaseNode {
                      int value_index);
 };
 
-// implementations
+/*!
+ * \brief base class of operation node.
+ */
+class OperationNode : public Node {
+ public:
+  /*! \brief The domain of iteration of this op. */
+  Domain domain;
+  /*! \brief iter-Var over the dimensions */
+  Array<Var> dim_var;
+  /*! \brief optional name of the operation */
+  std::string name;
+  /*! \return number of outputs of this op */
+  virtual size_t num_outputs() const = 0;
+  /*! \return name of i-th output */
+  virtual std::string output_name(size_t i) const = 0;
+  /*! \return type of i-th output */
+  virtual Type output_dtype(size_t i) const = 0;
+  /*! \return shape of i-th output */
+  virtual Array<Expr> output_shape(size_t i) const = 0;
+};
+
+// Implementations of inline functions
+inline const OperationNode* Operation::operator->() const {
+  return static_cast<const OperationNode*>(node_.get());
+}
 
 inline const TensorNode* Tensor::operator->() const {
   return static_cast<const TensorNode*>(node_.get());
diff --git a/src/lang/operation.cc b/src/lang/operation.cc
index c1634c354..49625f158 100644
--- a/src/lang/operation.cc
+++ b/src/lang/operation.cc
@@ -10,12 +10,9 @@
 namespace tvm {
 
 Tensor Compute(Array<Expr> shape, FCompute fcompute, std::string name) {
-  auto node = std::make_shared<TensorNode>();
   auto op_node = std::make_shared<ComputeOpNode>();
-  node->name = name;
-  node->shape = shape;
   // compute dimension.
-  size_t ndim = node->shape.size();
+  size_t ndim = shape.size();
   std::vector<Var> dim_index;
   for (size_t i = 0; i < ndim; ++i) {
     std::ostringstream os;
@@ -32,10 +29,8 @@ Tensor Compute(Array<Expr> shape, FCompute fcompute, std::string name) {
   op_node->domain = Domain(dom);
   op_node->body = fcompute(op_node->dim_var);
   op_node->name = name;
-  node->dtype = op_node->body.type();
-  node->op = Operation(op_node);
-  node->value_index = 0;
-  return Tensor(node);
+
+  return Operation(op_node).output(0);
 }
 
 Operation ComputeOpNode::make(Domain domain,
@@ -50,6 +45,37 @@ Operation ComputeOpNode::make(Domain domain,
   return Operation(n);
 }
 
+Tensor Operation::output(size_t i) const {
+  auto node = std::make_shared<TensorNode>();
+  node->op = *this;
+  node->value_index = 0;
+  node->name =  (*this)->output_name(i);
+  node->dtype = (*this)->output_dtype(i);
+  node->shape = (*this)->output_shape(i);
+  return Tensor(node);
+}
+
+std::string ComputeOpNode::output_name(size_t i) const {
+  CHECK_EQ(i, 0);
+  return name;
+}
+
+Type ComputeOpNode::output_dtype(size_t i) const {
+  CHECK_EQ(i, 0);
+  return body.type();
+}
+
+Array<Expr> ComputeOpNode::output_shape(size_t i) const {
+  CHECK_EQ(i, 0);
+  std::vector<Expr> shape;
+  for (size_t i = 0; i < domain.size(); ++i) {
+    shape.push_back(domain[i]->extent);
+  }
+  return Array<Expr>(shape);
+}
+
+
+
 TVM_REGISTER_NODE_TYPE(ComputeOpNode);
 
 }  // namespace tvm
diff --git a/src/pass/schedule_ops.cc b/src/pass/schedule_ops.cc
new file mode 100644
index 000000000..e71385826
--- /dev/null
+++ b/src/pass/schedule_ops.cc
@@ -0,0 +1,24 @@
+/*!
+ *  Copyright (c) 2016 by Contributors
+ * \file schedule_ops.cc
+ */
+#include <tvm/ir.h>
+#include <tvm/ir_mutator.h>
+#include <tvm/ir_pass.h>
+
+namespace tvm {
+namespace ir {
+namespace {
+
+// inject the operator's realization on the stmt.
+class InjectRealize : public IRMutator {
+ public:
+  explicit InjectRealize(std::vector<Tensor> tensors)
+      : tensors_(tensors) {}
+  std::vector<Tensor> tensors_;
+};
+
+
+}  // namespace
+}  // namespace ir
+}  // namespace tvm
diff --git a/tests/python/test_tensor.py b/tests/python/test_tensor.py
index a9cc09fbf..1eb6b3ba1 100644
--- a/tests/python/test_tensor.py
+++ b/tests/python/test_tensor.py
@@ -8,7 +8,7 @@ def test_tensor():
     B = tvm.placeholder((n, l), name='B')
     T = tvm.compute((m, n, l), lambda i, j, k: A(i, k) * B(j, k))
 
-    print(T.source)
+    print(T.op.body)
     assert(tuple(T.shape) == (m, n, l))
     assert(A.source is None)
 
@@ -21,7 +21,7 @@ def test_tensor_reduce():
     T = tvm.compute((m, n, l), lambda i, j, k: A(i, k) * B(j, k))
     rd = tvm.RDomain(tvm.Range(A.shape[1]))
     C = tvm.compute((m, n), lambda i, j: tvm.sum(T(i, j, rd.index[0]), rdom=rd))
-    print(C.source)
+    print(C.op.body)
 
 if __name__ == "__main__":
     test_tensor()
-- 
GitLab