Fix phi bug on exception edges.

Change-Id: Icb6bf5b2ee87a12a9728166a588ef7259dfa88df
diff --git a/src/compiler_llvm/gbc_expander.cc b/src/compiler_llvm/gbc_expander.cc
index 88505ee..412dbf7 100644
--- a/src/compiler_llvm/gbc_expander.cc
+++ b/src/compiler_llvm/gbc_expander.cc
@@ -32,6 +32,8 @@
 #include <llvm/Support/InstIterator.h>
 
 #include <vector>
+#include <map>
+#include <utility>
 
 using namespace art;
 using namespace compiler_llvm;
@@ -69,6 +71,9 @@
   std::vector<llvm::BasicBlock*> basic_blocks_;
 
   std::vector<llvm::BasicBlock*> basic_block_landing_pads_;
+  llvm::BasicBlock* old_basic_block_;
+  std::map<llvm::BasicBlock*, std::vector<std::pair<llvm::BasicBlock*, llvm::BasicBlock*> > >
+      landing_pad_phi_mapping_;
   llvm::BasicBlock* basic_block_unwind_;
 
   bool changed_;
@@ -418,11 +423,15 @@
   // because we will create new basic block while expanding the intrinsics.
   // We only want to iterate through the input basic blocks.
 
+  landing_pad_phi_mapping_.clear();
+
   for (llvm::Function::iterator bb_iter = func_->begin();
        num_basic_blocks > 0; ++bb_iter, --num_basic_blocks) {
     // Set insert point to current basic block.
     irb_.SetInsertPoint(bb_iter);
 
+    old_basic_block_ = bb_iter;
+
     // Rewrite the basic block
     RewriteBasicBlock(bb_iter);
 
@@ -432,6 +441,73 @@
       UpdatePhiInstruction(bb_iter, last_block);
     }
   }
+
+  typedef std::map<llvm::PHINode*, llvm::PHINode*> HandlerPHIMap;
+  HandlerPHIMap handler_phi;
+  // Iterate every used landing pad basic block
+  for (size_t i = 0, ei = basic_block_landing_pads_.size(); i != ei; ++i) {
+    llvm::BasicBlock* lbb = basic_block_landing_pads_[i];
+    if (lbb == NULL) {
+      continue;
+    }
+
+    llvm::TerminatorInst* term_inst = lbb->getTerminator();
+    std::vector<std::pair<llvm::BasicBlock*, llvm::BasicBlock*> >& rewrite_pair
+        = landing_pad_phi_mapping_[lbb];
+    irb_.SetInsertPoint(lbb->begin());
+
+    // Iterate every succeeding basic block (catch block)
+    for (unsigned succ_iter = 0, succ_end = term_inst->getNumSuccessors();
+         succ_iter != succ_end; ++succ_iter) {
+      llvm::BasicBlock* succ_basic_block = term_inst->getSuccessor(succ_iter);
+
+      // Iterate every phi instructions in the succeeding basic block
+      for (llvm::BasicBlock::iterator
+           inst_iter = succ_basic_block->begin(),
+           inst_end = succ_basic_block->end();
+           inst_iter != inst_end; ++inst_iter) {
+        llvm::PHINode *phi = llvm::dyn_cast<llvm::PHINode>(inst_iter);
+
+        if (!phi) {
+          break; // Meet non-phi instruction.  Done.
+        }
+
+        if (handler_phi[phi] == NULL) {
+          handler_phi[phi] = llvm::PHINode::Create(phi->getType(), 1);
+        }
+
+        // Create new_phi in landing pad
+        llvm::PHINode* new_phi = irb_.CreatePHI(phi->getType(), rewrite_pair.size());
+        // Insert all incoming value into new_phi by rewrite_pair
+        for (size_t j = 0, ej = rewrite_pair.size(); j != ej; ++j) {
+          llvm::BasicBlock* old_bb = rewrite_pair[j].first;
+          llvm::BasicBlock* new_bb = rewrite_pair[j].second;
+          new_phi->addIncoming(phi->getIncomingValueForBlock(old_bb), new_bb);
+        }
+        // Delete all incoming value from phi by rewrite_pair
+        for (size_t j = 0, ej = rewrite_pair.size(); j != ej; ++j) {
+          llvm::BasicBlock* old_bb = rewrite_pair[j].first;
+          int old_bb_idx = phi->getBasicBlockIndex(old_bb);
+          if (old_bb_idx >= 0) {
+            phi->removeIncomingValue(old_bb_idx, false);
+          }
+        }
+        // Insert new_phi into new handler phi
+        handler_phi[phi]->addIncoming(new_phi, lbb);
+      }
+    }
+  }
+
+  // Replace all handler phi
+  // We can't just use the old handler phi, because some exception edges will disappear after we
+  // compute fast-path.
+  for (HandlerPHIMap::iterator it = handler_phi.begin(); it != handler_phi.end(); ++it) {
+    llvm::PHINode* old_phi = it->first;
+    llvm::PHINode* new_phi = it->second;
+    new_phi->insertBefore(old_phi);
+    old_phi->replaceAllUsesWith(new_phi);
+    old_phi->eraseFromParent();
+  }
 }
 
 void GBCExpanderPass::UpdatePhiInstruction(llvm::BasicBlock* old_basic_block,
@@ -2522,6 +2598,8 @@
 
 void GBCExpanderPass::EmitBranchExceptionLandingPad(uint32_t dex_pc) {
   if (llvm::BasicBlock* lpad = GetLandingPadBasicBlock(dex_pc)) {
+    landing_pad_phi_mapping_[lpad].push_back(std::make_pair(old_basic_block_,
+                                                            irb_.GetInsertBlock()));
     irb_.CreateBr(lpad);
   } else {
     irb_.CreateBr(GetUnwindBasicBlock());
@@ -2534,6 +2612,8 @@
   llvm::BasicBlock* block_cont = CreateBasicBlockWithDexPC(dex_pc, "cont");
 
   if (llvm::BasicBlock* lpad = GetLandingPadBasicBlock(dex_pc)) {
+    landing_pad_phi_mapping_[lpad].push_back(std::make_pair(old_basic_block_,
+                                                            irb_.GetInsertBlock()));
     irb_.CreateCondBr(exception_pending, lpad, block_cont, kUnlikely);
   } else {
     irb_.CreateCondBr(exception_pending, GetUnwindBasicBlock(), block_cont, kUnlikely);