diff --git a/llvm/lib/Transforms/ApproxScheduler/ApproxScheduler.cpp b/llvm/lib/Transforms/ApproxScheduler/ApproxScheduler.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..41d8343417a389e9e04692876d8b519e9247bb3c
--- /dev/null
+++ b/llvm/lib/Transforms/ApproxScheduler/ApproxScheduler.cpp
@@ -0,0 +1,259 @@
+//===------------------------ InPlaceDFGAnalysis.cpp ----------------------===//
+//
+//
+//
+//                     The LLVM Compiler Infrastructure
+//
+//
+//
+// This file is distributed under the University of Illinois Open Source
+//
+// License. See LICENSE.TXT for details.
+//
+//
+//
+//===----------------------------------------------------------------------===//
+
+#define DEBUG_TYPE "ApproxScheduler"
+
+#include "llvm/IR/Module.h"
+#include "llvm/Pass.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/InPlaceDFG/InPlaceDFGAnalysis.h"
+#include "llvm/SupportVISC/DFG2LLVM.h"
+#include "llvm/IR/InstrTypes.h"
+#include <unordered_map>
+#include <dirent.h>
+#include <stdio.h>
+#include <sstream>
+#include <fstream>
+
+
+using namespace llvm;
+using namespace builddfg;
+using namespace dfg2llvm;
+using namespace inplacedfg;
+
+
+namespace {
+
+static cl::opt<std::string> category_input("category", cl::desc(" Hardware-agnostic ranking cateogy {log, linear, quad} "));
+static cl::opt<int> rank_input("rank", cl::desc(" Hardware-agostic rank given by autotuner "));
+
+
+struct ApproxMetrics{
+  std::string op_name;
+  std::string category;
+  unsigned int rank; // rank given by autotuner
+  double approx_level;
+  // Relative L-norm metrics
+  double relative_l1;
+  double relative_l2;
+  double relative_linf;
+  // Mean L-norm metrics
+  double mean_l1;
+  double mean_l2;
+  double mean_linf;
+};    
+
+  
+  
+  
+struct ApproxSchedulerWrapperPass : public ModulePass {
+  static char ID; // Pass identification, replacement for typeid
+  ApproxSchedulerWrapperPass() : ModulePass(ID) {}
+    
+public:
+  // Functions
+  bool runOnModule(Module &M);
+  void getAnalysisUsage(AnalysisUsage &AU) const;
+};
+
+
+// Visitor for Code generation traversal (tree traversal for now)
+class ApproxScheduler : public CodeGenTraversal {
+
+private:
+
+  int rank; // Rank to use for scheduling - ranks added in operand bundles
+  std::string category; // category = {log, linear, quad}
+  
+  // Virtual Functions
+  void init() {}
+  void initRuntimeAPI() {}
+  void codeGen(DFInternalNode* N);
+  void codeGen(DFLeafNode* N);
+  bool rankMatches(OperandBundleUse opBundle, std::string category, int rank);
+  ApproxMetrics* getApproxInfo(Instruction* I);
+  ApproxMetrics* loadApproxMetrics(OperandBundleUse opBundle);
+  
+  // Tracks the id of the tensor op processed
+  unsigned int currentID;
+
+public:
+  // Constructor
+  ApproxScheduler(Module &_M, BuildDFG &_DFG, std::string category, int rank);  
+  void run();
+
+};
+
+  
+
+void ApproxSchedulerWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const {
+  AU.addRequired<BuildDFG>();
+  AU.addPreserved<BuildDFG>();
+}
+
+    
+bool ApproxSchedulerWrapperPass::runOnModule(Module &M) {
+
+  BuildDFG &DFG = getAnalysis<BuildDFG>();
+
+  std::string category = category_input.getValue();
+  int rank = rank_input.getValue();
+  
+  ApproxScheduler scheduler(M, DFG, category, rank);
+  scheduler.run();
+
+  return true;
+}
+
+
+  
+ApproxScheduler::ApproxScheduler(Module &_M, BuildDFG &_DFG, std::string category, int rank) :
+    CodeGenTraversal(_M, _DFG){
+
+  this->category = category;
+  this->rank = rank;
+}
+
+  
+void ApproxScheduler::run() {
+
+  errs() << "\n NOTE: Approximation-based scheduling transform \n";
+  std::vector<DFInternalNode*> Roots = DFG.getRoots();
+
+  // Iterate over all the DFGs
+  for (auto rootNode: Roots) {
+   this->visit(rootNode);
+  }
+
+  return;
+}
+
+
+/*** Analysis of internal node ***/
+void ApproxScheduler::codeGen(DFInternalNode* N) {
+  DEBUG(errs() << "Analysing Node: " << N->getFuncPointer()->getName() << "\n");
+}
+
+
+ApproxMetrics* ApproxScheduler::loadApproxMetrics(OperandBundleUse opBundle){
+
+}
+
+
+bool ApproxScheduler::rankMatches(OperandBundleUse opBundle, std::string category_in, int rank_in){
+
+  // Extracting value of the 'category' attribute
+  GlobalVariable* gv = dyn_cast<GlobalVariable>(opBundle.Inputs[1].get());
+  ConstantDataArray* constString = dyn_cast<ConstantDataArray>(gv->getInitializer());
+  std::string category = std::string(constString->getAsCString().data());
+  errs()<<"*category = "<<category<<"\n";
+
+  int rank = dyn_cast<ConstantInt>(opBundle.Inputs[3].get())->getZExtValue();
+  errs()<<"-rank = "<<rank<<"\n";
+
+  if(category == category_in && rank == rank_in)
+    return true;
+  else
+    return false;
+
+   /*for(unsigned int j = 0; j < bundleUse.Inputs.size(); j++){
+       Value* bundleVal = bundleUse.Inputs[j].get();
+       errs()<<"Val = "<<*bundleVal<<"\n";
+    } */
+}
+  
+  
+ApproxMetrics* ApproxScheduler::getApproxInfo(Instruction* I){
+
+  CallSite* CS = new CallSite(I);
+  if(CS->hasOperandBundles()){
+    errs()<<"CallSite has OperandBundles \n";
+
+    for(unsigned int i = 0; i < CS->getNumOperandBundles(); i++){
+      OperandBundleUse bundleUse = CS->getOperandBundleAt(i);
+      errs()<<"bundleUse -> getTagName() = "<<bundleUse.getTagName()<<"\n";
+
+      if(rankMatches(bundleUse, category, rank)){
+        return loadApproxMetrics(bundleUse);
+      }
+    
+      /*for(unsigned int j = 0; j < bundleUse.Inputs.size(); j++){
+	Value* bundleVal = bundleUse.Inputs[j].get();
+	errs()<<"Val = "<<*bundleVal<<"\n";
+      }
+      */
+	  
+    }	
+  }
+  else{
+    errs()<<"DOES NOT have OperandBundles \n";
+  }
+
+  assert("No Bundle Matched the provided rank and Category! \n");
+
+}
+  
+  
+/*** Analysis of leaf node ***/
+void ApproxScheduler::codeGen(DFLeafNode* N) {
+  DEBUG(errs() << "Analysing Node: " << N->getFuncPointer()->getName() << "\n");
+
+  // Skip code generation if it is a dummy node
+  if(N->isDummyNode()) {
+    DEBUG(errs() << "Skipping dummy node\n");
+    return;
+  }
+
+  // Abort code generation if it is an allocation node
+  if(N->isAllocationNode()) {
+    assert(false && "Allocation Node not expected in ApproxHPVM");
+    return;
+  }
+
+  Function *F = N->getFuncPointer();
+  Module* M = F->getParent();
+
+  /**** Reading all tensor operations in the DFG Leaf Node ****/
+  for (inst_iterator i = inst_begin(F), e = inst_end(F); i != e; ++i) {
+    Instruction *I = &(*i);
+    errs()<<*I<<"\n";
+
+    if (BuildDFG::isViscIntrinsic(I)) {
+      IntrinsicInst* II = dyn_cast<IntrinsicInst>(I);
+      // FIXME: The assumption of only tensor instrinsics is restrictive
+      assert((II->getCalledFunction()->getName()).startswith("llvm.visc.tensor")
+	     && "Only HPVM tensor intrinsics allowed in ApproxHPVM leaf nodes\n");
+   
+      // NOTE: Get tensorOp name - the scheduling decisions are made per-operation type 
+      std::string intrinsic_id = std::string(II->getCalledFunction()->getName().data());
+      ApproxMetrics* approx_metrics = getApproxInfo(I);
+      
+    }
+
+  }
+  
+}
+
+char ApproxSchedulerWrapperPass::ID = 0;
+static RegisterPass<ApproxSchedulerWrapperPass> X("approx-scheduler",
+  "Select target compute unit based on aprroximation metrics",
+  false /* does not modify the CFG */,
+  false /* not transformation, just analysis */);
+
+
+  
+} // End of namespace
+
diff --git a/llvm/lib/Transforms/ApproxScheduler/CMakeLists.txt b/llvm/lib/Transforms/ApproxScheduler/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..267ad1d859ccac891b956c4e2210e42ce25e4aed
--- /dev/null
+++ b/llvm/lib/Transforms/ApproxScheduler/CMakeLists.txt
@@ -0,0 +1,12 @@
+if(WIN32 OR CYGWIN)
+  set(LLVM_LINK_COMPONENTS Core Support)
+endif()
+
+add_llvm_loadable_module( ApproxScheduler
+  ApproxScheduler.cpp
+
+  DEPENDS
+  intrinsics_gen
+  PLUGIN_TOOL
+  opt
+  )
diff --git a/llvm/lib/Transforms/ApproxScheduler/LLVMBuild.txt b/llvm/lib/Transforms/ApproxScheduler/LLVMBuild.txt
new file mode 100644
index 0000000000000000000000000000000000000000..ccd8479c2e538bba60678debe01d05011658a5f4
--- /dev/null
+++ b/llvm/lib/Transforms/ApproxScheduler/LLVMBuild.txt
@@ -0,0 +1,21 @@
+;===- ./lib/Transforms/LocalMem/LLVMBuild.txt ------------------*- Conf -*--===;
+;
+;                     The LLVM Compiler Infrastructure
+;
+; This file is distributed under the University of Illinois Open Source
+; License. See LICENSE.TXT for details.
+;
+;===------------------------------------------------------------------------===;
+;
+; This is an LLVMBuild description file for the components in this subdirectory.
+;
+; For more information on the LLVMBuild system, please see:
+;
+;   http://llvm.org/docs/LLVMBuild.html
+;
+;===------------------------------------------------------------------------===;
+
+[component_0]
+type = Library
+name = ApproxScheduler
+parent = Transforms
diff --git a/llvm/lib/Transforms/CMakeLists.txt b/llvm/lib/Transforms/CMakeLists.txt
index b7ab50b6f798a0d1818172474c93a8ad5275f00e..a189075fff07ece58c2da01909fde4f77cf8954d 100644
--- a/llvm/lib/Transforms/CMakeLists.txt
+++ b/llvm/lib/Transforms/CMakeLists.txt
@@ -17,6 +17,7 @@ add_subdirectory(DFG2LLVM_X86)
 add_subdirectory(LocalMem)
 add_subdirectory(InPlaceDFG)
 add_subdirectory(InsertApproxInfo)
+add_subdirectory(ApproxScheduler)
 add_subdirectory(GenVISC)
 add_subdirectory(MergeDFN)
 add_subdirectory(FuseHPVMTensorNodes)
diff --git a/llvm/test/VISC/DNN_Benchmarks/benchmarks/lenet/bin/approximate.py b/llvm/test/VISC/DNN_Benchmarks/benchmarks/lenet/bin/approximate.py
index e07db1c0dfd5c99de5eaa6a992249054f72fab3c..c77d43bf8ff554b77623ed0ea291d4590e52cb3a 100644
--- a/llvm/test/VISC/DNN_Benchmarks/benchmarks/lenet/bin/approximate.py
+++ b/llvm/test/VISC/DNN_Benchmarks/benchmarks/lenet/bin/approximate.py
@@ -16,17 +16,23 @@ num_flags = 14 # FIXME: Auto-extract the number of tensor ops from the bitcode f
 error_range = 9
 
 
+def change_dir():
+    os.chdir(bench_build_dir)
+    print os.getcwd()
 
-def build_binaries():
+def setup_env():
+    os.environ["LD_LIBRARY_PATH"] = os.environ["LD_LIBRARY_PATH"] + ":" + os.environ["LLVM_BUILD_ROOT"] + "/lib" 
+    print os.environ["LD_LIBRARY_PATH"]
 
+    
+def build_binaries():
     subprocess.call("make", shell=True)
     
 
 def run_autotuner():
 
     # Change build directory to benchmark build directory
-    os.chdir(bench_build_dir)
-    print os.getcwd()
+    change_dir()
 
     LLVM_SRC_ROOT = os.environ["LLVM_SRC_ROOT"]
     autotuner_cmd = "python  " + LLVM_SRC_ROOT + "projects/hpvm-tensor-rt/opentuner/autotuner/approxhpvm_tuner.py " + \
@@ -44,25 +50,38 @@ def run_autotuner():
 
 def add_approx_info():
 
-    os.chdir(bench_build_dir)
-    print os.getcwd()
-    os.environ["LD_LIBRARY_PATH"] = os.environ["LD_LIBRARY_PATH"] + ":" + os.environ["LLVM_BUILD_ROOT"] + "/lib" 
-    print os.environ["LD_LIBRARY_PATH"]
-    
+    # Change directory and setup env variables
+    change_dir()
+    setup_env()
+
+    subprocess.call("which opt", shell=True)
+
     approxinfo_cmd = "opt  -load LLVMBuildDFG.so  -load InsertApproxInfo.so  -insert-approxinfo --results-dir " + \
                      result_dir + " " + " " + \
-                     visc_file_name + " -o " + visc_file_name + "_approx"
+                     visc_file_name + " -S -o " + visc_file_name + "_approx.ll"
 
-    print approxinfo_cmd
-    
+    print approxinfo_cmd    
     subprocess.call(approxinfo_cmd, shell=True)
 
+
+
+    
+def run_scheduler():
+
+    change_dir()
+    setup_env()
+
+    sched_cmd = "opt  -load LLVMBuildDFG.so  -load ApproxScheduler.so  -approx-scheduler --category quad --rank 4 " + \
+                     visc_file_name + "_approx.ll" + " -S -o " + visc_file_name + "_sched_out.ll"
+    print sched_cmd    
+    subprocess.call(sched_cmd, shell=True)
     
     
     
 if __name__ == "__main__":
 
     #build_binaries()
-    run_autotuner()
-    add_approx_info()
+    #run_autotuner()
+    #add_approx_info()
+    run_scheduler()