Only do the suspend check at return and loop latch.

Change-Id: I0c7d2b25288bfb85dfc8a0650b75aff2162f9903
diff --git a/src/compiler_llvm/compilation_unit.cc b/src/compiler_llvm/compilation_unit.cc
index ae6e0a2..f11fdaf 100644
--- a/src/compiler_llvm/compilation_unit.cc
+++ b/src/compiler_llvm/compilation_unit.cc
@@ -31,8 +31,11 @@
 #include <llvm/ADT/Triple.h>
 #include <llvm/Analysis/CallGraph.h>
 #include <llvm/Analysis/DebugInfo.h>
+#include <llvm/Analysis/Dominators.h>
+#include <llvm/Analysis/LoopInfo.h>
 #include <llvm/Analysis/LoopPass.h>
 #include <llvm/Analysis/RegionPass.h>
+#include <llvm/Analysis/ScalarEvolution.h>
 #include <llvm/Analysis/Verifier.h>
 #include <llvm/Assembly/PrintModulePass.h>
 #include <llvm/Bitcode/ReaderWriter.h>
@@ -63,6 +66,7 @@
 #include <llvm/Target/TargetMachine.h>
 #include <llvm/Transforms/IPO.h>
 #include <llvm/Transforms/IPO/PassManagerBuilder.h>
+#include <llvm/Transforms/Scalar.h>
 
 #include <sys/types.h>
 #include <sys/wait.h>
@@ -102,6 +106,59 @@
 llvm::RegisterPass<UpdateFrameSizePass> reg_update_frame_size_pass_(
   "update-frame-size", "Update frame size pass", false, false);
 
+
+// TODO: We may need something to manage these passes.
+// TODO: We need high-level IR to analysis and do this at the IRBuilder level.
+class AddSuspendCheckToLoopLatchPass : public llvm::LoopPass {
+ public:
+  static char ID;
+
+  AddSuspendCheckToLoopLatchPass() : llvm::LoopPass(ID), irb_(NULL) {
+    LOG(FATAL) << "Unexpected instantiation of AddSuspendCheckToLoopLatchPass";
+    // NOTE: We have to declare this constructor for llvm::RegisterPass, but
+    // this constructor won't work because we have no information on
+    // IRBuilder.  Thus, we should place a LOG(FATAL) here.
+  }
+
+  AddSuspendCheckToLoopLatchPass(art::compiler_llvm::IRBuilder* irb)
+    : llvm::LoopPass(ID), irb_(irb) {
+  }
+
+  virtual void getAnalysisUsage(llvm::AnalysisUsage &AU) const {
+    AU.addRequiredID(llvm::LoopSimplifyID);
+
+    AU.addPreserved<llvm::DominatorTree>();
+    AU.addPreserved<llvm::LoopInfo>();
+    AU.addPreservedID(llvm::LoopSimplifyID);
+    AU.addPreserved<llvm::ScalarEvolution>();
+    AU.addPreservedID(llvm::BreakCriticalEdgesID);
+  }
+
+  virtual bool runOnLoop(llvm::Loop *loop, llvm::LPPassManager &lpm) {
+    CHECK_EQ(loop->getNumBackEdges(), 1U) << "Loop must be simplified!";
+    llvm::BasicBlock* bb = loop->getLoopLatch();
+    CHECK_NE(bb, static_cast<void*>(NULL)) << "A single loop latch must exist.";
+
+    irb_->SetInsertPoint(bb->getTerminator());
+
+    using namespace art::compiler_llvm::runtime_support;
+    llvm::Value* runtime_func = irb_->GetRuntime(TestSuspend);
+    llvm::Value* thread_object_addr = irb_->CreateCall(irb_->GetRuntime(GetCurrentThread));
+    irb_->CreateCall(runtime_func, thread_object_addr);
+
+    return true;
+  }
+
+ private:
+  art::compiler_llvm::IRBuilder* irb_;
+};
+
+char AddSuspendCheckToLoopLatchPass::ID = 0;
+
+llvm::RegisterPass<AddSuspendCheckToLoopLatchPass> reg_add_suspend_check_to_loop_latch_pass_(
+  "add-suspend-check-to-loop-latch", "Add suspend check to loop latch pass", false, false);
+
+
 } // end anonymous namespace
 
 namespace art {
@@ -145,27 +202,6 @@
 }
 
 
-bool CompilationUnit::WriteBitcodeToFile(const std::string& bitcode_filename) {
-  MutexLock GUARD(cunit_lock_);
-  std::string errmsg;
-
-  llvm::OwningPtr<llvm::tool_output_file> out_file(
-    new llvm::tool_output_file(bitcode_filename.c_str(), errmsg,
-                               llvm::raw_fd_ostream::F_Binary));
-
-
-  if (!errmsg.empty()) {
-    LOG(ERROR) << "Failed to create bitcode output file: " << errmsg;
-    return false;
-  }
-
-  llvm::WriteBitcodeToFile(module_, out_file->os());
-  out_file->keep();
-
-  return true;
-}
-
-
 bool CompilationUnit::Materialize(size_t thread_count) {
   MutexLock GUARD(cunit_lock_);
 
@@ -360,6 +396,39 @@
   llvm::FunctionPassManager fpm(module_);
   fpm.add(new llvm::TargetData(*target_data));
 
+  if (bitcode_filename_.empty()) {
+    // If we don't need write the bitcode to file, add the AddSuspendCheckToLoopLatchPass to the
+    // regular FunctionPass.
+    fpm.add(new ::AddSuspendCheckToLoopLatchPass(irb_.get()));
+  } else {
+    // Run AddSuspendCheckToLoopLatchPass before we write the bitcode to file.
+    llvm::FunctionPassManager fpm2(module_);
+    fpm2.add(new ::AddSuspendCheckToLoopLatchPass(irb_.get()));
+    fpm2.doInitialization();
+    for (llvm::Module::iterator F = module_->begin(), E = module_->end();
+         F != E; ++F) {
+      fpm2.run(*F);
+    }
+    fpm2.doFinalization();
+
+
+    // Write bitcode to file
+    std::string errmsg;
+
+    llvm::OwningPtr<llvm::tool_output_file> out_file(
+      new llvm::tool_output_file(bitcode_filename_.c_str(), errmsg,
+                                 llvm::raw_fd_ostream::F_Binary));
+
+
+    if (!errmsg.empty()) {
+      LOG(ERROR) << "Failed to create bitcode output file: " << errmsg;
+      return false;
+    }
+
+    llvm::WriteBitcodeToFile(module_, out_file->os());
+    out_file->keep();
+  }
+
   // Add optimization pass
   llvm::PassManagerBuilder pm_builder;
   //pm_builder.Inliner = llvm::createFunctionInliningPass();
diff --git a/src/compiler_llvm/compilation_unit.h b/src/compiler_llvm/compilation_unit.h
index a92dabe..40a4c73 100644
--- a/src/compiler_llvm/compilation_unit.h
+++ b/src/compiler_llvm/compilation_unit.h
@@ -88,7 +88,10 @@
     return num_elf_funcs_++;
   }
 
-  bool WriteBitcodeToFile(const std::string& bitcode_filename);
+  void SetBitcodeFileName(const std::string& bitcode_filename) {
+    MutexLock GUARD(cunit_lock_);
+    bitcode_filename_ = bitcode_filename;
+  }
 
   bool Materialize(size_t thread_count);
 
@@ -122,6 +125,7 @@
   UniquePtr<RuntimeSupportBuilder> runtime_support_;
   llvm::Module* module_;
 
+  std::string bitcode_filename_;
   std::string elf_image_;
 
   SafeMap<const llvm::Function*, CompiledMethod*> compiled_methods_map_;
diff --git a/src/compiler_llvm/compiler_llvm.cc b/src/compiler_llvm/compiler_llvm.cc
index 681b367..dce7f91 100644
--- a/src/compiler_llvm/compiler_llvm.cc
+++ b/src/compiler_llvm/compiler_llvm.cc
@@ -178,7 +178,7 @@
   // Write bitcode to file when filename is set
   if (IsBitcodeFileNameAvailable()) {
     const size_t cunit_idx = cunits_.size();
-    cunit->WriteBitcodeToFile(
+    cunit->SetBitcodeFileName(
       StringPrintf("%s-%zu", bitcode_filename_.c_str(), cunit_idx));
   }
 
diff --git a/src/compiler_llvm/method_compiler.cc b/src/compiler_llvm/method_compiler.cc
index 1cc6a30..c5606c7 100644
--- a/src/compiler_llvm/method_compiler.cc
+++ b/src/compiler_llvm/method_compiler.cc
@@ -1928,11 +1928,6 @@
 
   int32_t branch_offset = dec_insn.vA;
 
-  if (branch_offset <= 0) {
-    // Garbage collection safe-point on backward branch
-    EmitGuard_GarbageCollectionSuspend(dex_pc);
-  }
-
   irb_.CreateBr(GetBasicBlock(dex_pc + branch_offset));
 }
 
@@ -2063,11 +2058,6 @@
 
   int32_t branch_offset = dec_insn.vC;
 
-  if (branch_offset <= 0) {
-    // Garbage collection safe-point on backward branch
-    EmitGuard_GarbageCollectionSuspend(dex_pc);
-  }
-
   llvm::Value* src1_value;
   llvm::Value* src2_value;
 
@@ -2129,11 +2119,6 @@
 
   int32_t branch_offset = dec_insn.vB;
 
-  if (branch_offset <= 0) {
-    // Garbage collection safe-point on backward branch
-    EmitGuard_GarbageCollectionSuspend(dex_pc);
-  }
-
   llvm::Value* src1_value;
   llvm::Value* src2_value;