diff --git a/include/tvm/tensor.h b/include/tvm/tensor.h
index 3df636f338edd07ee31107d30db0982f3615b051..60f5c5a2d505d9bc2420021632d351275992904d 100644
--- a/include/tvm/tensor.h
+++ b/include/tvm/tensor.h
@@ -239,4 +239,13 @@ DEFINE_OVERLOAD_SLICE_BINARY_OP(>);  // NOLINT(*)
 DEFINE_OVERLOAD_SLICE_BINARY_OP(<);  // NOLINT(*)
 
 }  // namespace tvm
+
+namespace std {
+template <>
+struct hash<::tvm::Operation> {
+  std::size_t operator()(const ::tvm::Operation& k) const {
+    return k.hash();
+  }
+};
+}
 #endif  // TVM_TENSOR_H_
diff --git a/src/README.md b/src/README.md
index 33f4e6cc49c73c90a6045f2a466348e9b15bfc07..d1d8201e02d8bf1c9d43809e8f6d94cbee4b4731 100644
--- a/src/README.md
+++ b/src/README.md
@@ -2,5 +2,5 @@
 
 - c_api  C API related functions
 - lang The definition of DSL related data structure
+- schedule The operations on the schedule graph before converting to IR.
 - pass The optimization pass on the IR structure
-- bound Bound inference logics.
diff --git a/src/bound/bound.cc b/src/schedule/bound.cc
similarity index 96%
rename from src/bound/bound.cc
rename to src/schedule/bound.cc
index 052920b932a6b20e7bb9395d8e433b50d0ec1a61..50a62e10432f37bd766e512a4eba85ee1d265ede 100644
--- a/src/bound/bound.cc
+++ b/src/schedule/bound.cc
@@ -8,7 +8,7 @@
 #include "./bound.h"
 
 namespace tvm {
-namespace bound {
+namespace schedule {
 
 // result = ceil((a / b)), both a and b are positive integer
 inline Expr DivCeil(Expr a, Expr b) {
@@ -89,5 +89,10 @@ void PassUp(const Schedule& s,
   }
 }
 
-}  // namespace bound
+
+std::unordered_map<IterVar, Range> InferBound(Schedule sch) {
+  return {};
+}
+
+}  // namespace schedule
 }  // namespace tvm
diff --git a/src/bound/bound.h b/src/schedule/bound.h
similarity index 78%
rename from src/bound/bound.h
rename to src/schedule/bound.h
index 5c73d832ae9cdee8e186d6d085b7bdb287925463..ac6becca35e2a21530a2f271c261af281bb8861b 100644
--- a/src/bound/bound.h
+++ b/src/schedule/bound.h
@@ -3,15 +3,15 @@
  * \file bound.h
  * \brief The bound inference logics on the schedule.
  */
-#ifndef TVM_BOUND_BOUND_H_
-#define TVM_BOUND_BOUND_H_
+#ifndef TVM_SCHEDULE_BOUND_H_
+#define TVM_SCHEDULE_BOUND_H_
 
 #include <tvm/expr.h>
 #include <tvm/schedule.h>
 #include <unordered_map>
 
 namespace tvm {
-namespace bound {
+namespace schedule {
 
 /*!
  * \brief Infer the bound of all iteration variables relates to the schedule.
@@ -21,7 +21,7 @@ namespace bound {
  */
 std::unordered_map<IterVar, Range> InferBound(Schedule sch);
 
-}  // namespace bound
+}  // namespace schedule
 }  // namespace tvm
 
-#endif  // TVM_BOUND_BOUND_H_
+#endif  // TVM_SCHEDULE_BOUND_H_
diff --git a/src/schedule/graph.cc b/src/schedule/graph.cc
new file mode 100644
index 0000000000000000000000000000000000000000..96ba4c986b40c6dc352ac480e332ab85d4e466e5
--- /dev/null
+++ b/src/schedule/graph.cc
@@ -0,0 +1,67 @@
+/*!
+ *  Copyright (c) 2016 by Contributors
+ * \file graph.cc
+ * \brief Utilities to get information about schedule graph.
+ */
+#include <tvm/ir.h>
+#include <tvm/ir_visitor.h>
+#include <unordered_set>
+#include "./int_set.h"
+#include "./graph.h"
+
+namespace tvm {
+namespace schedule {
+
+// construct a read graph that gives readers of each operation
+// that the root depend on
+ReadGraph CreateReadGraph(Operation root) {
+  std::unordered_map<Operation, std::vector<Tensor> > rmap;
+  rmap[root] = {};
+  std::vector<Operation> stack{root};
+  while (!stack.empty()) {
+    Operation r = stack.back();
+    stack.pop_back();
+    auto& vec = rmap.at(r);
+    if (r.as<ComputeOpNode>()) {
+      auto fvisit = [&vec, &rmap, &stack](const NodeRef& n) {
+        auto *call = n.as<ir::Call>();
+        if (call != nullptr && call->func.defined()) {
+          Tensor t(call->func.node_);
+          vec.push_back(t);
+          if (t->op.defined() && rmap.count(t->op) == 0) {
+            rmap[t->op] = {}; stack.push_back(t->op);
+          }
+        }
+      };
+      ir::PostOrderVisit(r.as<ComputeOpNode>()->body, fvisit);
+    } else {
+      LOG(FATAL) << "unknown operation mode";
+    }
+  }
+  return rmap;
+}
+
+
+void PostDFSOrder(const Operation& op,
+                    const ReadGraph& g,
+                    std::unordered_set<Operation>* visited,
+                    std::vector<Operation>* post_order) {
+  visited->insert(op);
+  for (const auto& t : g.at(op)) {
+    if (t->op.defined() && !visited->count(t->op)) {
+      PostDFSOrder(t->op, g, visited, post_order);
+    }
+  }
+  post_order->push_back(op);
+}
+
+std::vector<Operation> PostDFSOrder(
+    const Operation& root, const ReadGraph& g) {
+  std::unordered_set<Operation> visited;
+  std::vector<Operation> post_order;
+  PostDFSOrder(root, g, &visited, &post_order);
+  return post_order;
+}
+
+}  // namespace schedule
+}  // namespace tvm
diff --git a/src/schedule/graph.h b/src/schedule/graph.h
new file mode 100644
index 0000000000000000000000000000000000000000..cf57a213a036f4d17846da723ccd915f537576c4
--- /dev/null
+++ b/src/schedule/graph.h
@@ -0,0 +1,47 @@
+/*!
+ *  Copyright (c) 2016 by Contributors
+ * \file graph.h
+ * \brief Utilities to get information about schedule graph.
+ */
+#ifndef TVM_SCHEDULE_GRAPH_H_
+#define TVM_SCHEDULE_GRAPH_H_
+
+#include <tvm/expr.h>
+#include <tvm/schedule.h>
+#include <unordered_map>
+#include <vector>
+
+namespace tvm {
+namespace schedule {
+
+/*!
+ * \brief data structure of Operation->Tensors it reads
+ */
+using ReadGraph = std::unordered_map<Operation, std::vector<Tensor> >;
+
+/*!
+ * \brief Get read graph of each operation to all the
+ *  Tensors that it directly depends on.
+ *
+ *  The result map contains Operations needed to finish root Operation.
+ * \param root The root operation.
+ * \return The result map.
+ */
+ReadGraph CreateReadGraph(const Operation& root);
+
+/*!
+ * \brief Get a post DFS ordered of operations in the graph.
+ * \param root The root of the graph.
+ * \param g The read graph.
+ * \return vector order of Operations in PostDFS order.
+ *
+ * \note PostDFSOrder is a special case of Topoligical order,
+ *   and can be used when topoligical order is needed.
+ */
+std::vector<Operation> PostDFSOrder(
+    const Operation& root, const ReadGraph& g);
+
+}  // namespace schedule
+}  // namespace tvm
+
+#endif  // TVM_SCHEDULE_GRAPH_H_
diff --git a/src/bound/int_set.cc b/src/schedule/int_set.cc
similarity index 99%
rename from src/bound/int_set.cc
rename to src/schedule/int_set.cc
index 4a4c8a5740d51d269eb0bb7f39c4e2c91a38313f..8b05da931e2a1a99f21cc0ad0061055118c709cc 100644
--- a/src/bound/int_set.cc
+++ b/src/schedule/int_set.cc
@@ -7,7 +7,7 @@
 #include "./int_set.h"
 
 namespace tvm {
-namespace bound {
+namespace schedule {
 
 using namespace ir;
 
@@ -338,6 +338,5 @@ IntSet Eval(Expr e,
   return m.Eval(e);
 }
 
-}  // namespace bound
+}  // namespace schedule
 }  // namespace tvm
-
diff --git a/src/bound/int_set.h b/src/schedule/int_set.h
similarity index 95%
rename from src/bound/int_set.h
rename to src/schedule/int_set.h
index f5531ea4b86680f199ceaabd4796a91a92be9de6..dbcf497958eff25529917cb052937c255fb40abe 100644
--- a/src/bound/int_set.h
+++ b/src/schedule/int_set.h
@@ -3,14 +3,14 @@
  * \file int_set.h
  * \brief Abstraction for all integer set operations.
  */
-#ifndef TVM_BOUND_INT_SET_H_
-#define TVM_BOUND_INT_SET_H_
+#ifndef TVM_SCHEDULE_INT_SET_H_
+#define TVM_SCHEDULE_INT_SET_H_
 
 #include <tvm/expr.h>
 #include <tvm/schedule.h>
 
 namespace tvm {
-namespace bound {
+namespace schedule {
 
 // internal node container of int set.
 class IntSetNode;
@@ -97,7 +97,7 @@ void PassUp(const FuseNode* s,
  */
 IntSet Union(const Array<IntSet>& sets);
 
-}  // namespace bound
+}  // namespace schedule
 }  // namespace tvm
 
-#endif  // TVM_BOUND_INT_SET_H_
+#endif  // TVM_SCHEDULE_INT_SET_H_