Fix failing LLVM verification on unreachable blocks.

Bug: 8286478

The LLVM verifier fails if an unreachable block contains PHI instructions. This
happens in the Portable compiler when a catch block becomes unreachable.

This CL fixes the issue by ensuring catch blocks are always reachable. Under
some circumstances, they can be "virtually" reachable by creating fake
conditonal branch: "br i1 false, label %catch_block, label %next_insn". In
this case, we let LLVM delete these unreachable blocks.

Change-Id: I003c25492f32c0e7bbc8e32a48ec4ce47e2c8c32
diff --git a/src/compiler_llvm/gbc_expander.cc b/src/compiler_llvm/gbc_expander.cc
index ee81c07..0146542 100644
--- a/src/compiler_llvm/gbc_expander.cc
+++ b/src/compiler_llvm/gbc_expander.cc
@@ -294,12 +294,13 @@
                                   llvm::Value* denominator,
                                   JType op_jty);
 
-  void EmitGuard_NullPointerException(uint32_t dex_pc,
-                                      llvm::Value* object);
+  void EmitGuard_NullPointerException(uint32_t dex_pc, llvm::Value* object,
+                                      int opt_flags);
 
   void EmitGuard_ArrayIndexOutOfBoundsException(uint32_t dex_pc,
                                                 llvm::Value* array,
-                                                llvm::Value* index);
+                                                llvm::Value* index,
+                                                int opt_flags);
 
   llvm::FunctionType* GetFunctionType(uint32_t method_idx, bool is_static);
 
@@ -1352,12 +1353,9 @@
   llvm::Value* index_value = call_inst.getArgOperand(2);
   int opt_flags = LV2UInt(call_inst.getArgOperand(0));
 
-  if (!(opt_flags & MIR_IGNORE_NULL_CHECK)) {
-    EmitGuard_NullPointerException(dex_pc, array_addr);
-  }
-  if (!(opt_flags & MIR_IGNORE_RANGE_CHECK)) {
-    EmitGuard_ArrayIndexOutOfBoundsException(dex_pc, array_addr, index_value);
-  }
+  EmitGuard_NullPointerException(dex_pc, array_addr, opt_flags);
+  EmitGuard_ArrayIndexOutOfBoundsException(dex_pc, array_addr, index_value,
+                                           opt_flags);
 
   llvm::Value* array_elem_addr = EmitArrayGEP(array_addr, index_value, elem_jty);
 
@@ -1375,12 +1373,9 @@
   llvm::Value* index_value = call_inst.getArgOperand(3);
   int opt_flags = LV2UInt(call_inst.getArgOperand(0));
 
-  if (!(opt_flags & MIR_IGNORE_NULL_CHECK)) {
-    EmitGuard_NullPointerException(dex_pc, array_addr);
-  }
-  if (!(opt_flags & MIR_IGNORE_RANGE_CHECK)) {
-    EmitGuard_ArrayIndexOutOfBoundsException(dex_pc, array_addr, index_value);
-  }
+  EmitGuard_NullPointerException(dex_pc, array_addr, opt_flags);
+  EmitGuard_ArrayIndexOutOfBoundsException(dex_pc, array_addr, index_value,
+                                           opt_flags);
 
   new_value = TruncateCat1Types(new_value, elem_jty);
 
@@ -1408,9 +1403,7 @@
   uint32_t field_idx = LV2UInt(call_inst.getArgOperand(2));
   int opt_flags = LV2UInt(call_inst.getArgOperand(0));
 
-  if (!(opt_flags & MIR_IGNORE_NULL_CHECK)) {
-    EmitGuard_NullPointerException(dex_pc, object_addr);
-  }
+  EmitGuard_NullPointerException(dex_pc, object_addr, opt_flags);
 
   llvm::Value* field_value;
 
@@ -1477,9 +1470,7 @@
     new_value = irb_.CreateBitCast(new_value, irb_.getJType(field_jty));
   }
 
-  if (!(opt_flags & MIR_IGNORE_NULL_CHECK)) {
-    EmitGuard_NullPointerException(dex_pc, object_addr);
-  }
+  EmitGuard_NullPointerException(dex_pc, object_addr, opt_flags);
 
   int field_offset;
   bool is_volatile;
@@ -1901,9 +1892,7 @@
   llvm::Value* object_addr = call_inst.getArgOperand(1);
   int opt_flags = LV2UInt(call_inst.getArgOperand(0));
 
-  if (!(opt_flags & MIR_IGNORE_NULL_CHECK)) {
-    EmitGuard_NullPointerException(dex_pc, object_addr);
-  }
+  EmitGuard_NullPointerException(dex_pc, object_addr, opt_flags);
 
   EmitUpdateDexPC(dex_pc);
 
@@ -1917,9 +1906,7 @@
   llvm::Value* object_addr = call_inst.getArgOperand(1);
   int opt_flags = LV2UInt(call_inst.getArgOperand(0));
 
-  if (!(opt_flags & MIR_IGNORE_NULL_CHECK)) {
-    EmitGuard_NullPointerException(dex_pc, object_addr);
-  }
+  EmitGuard_NullPointerException(dex_pc, object_addr, opt_flags);
 
   EmitUpdateDexPC(dex_pc);
 
@@ -2117,12 +2104,12 @@
       EmitCallRuntimeForCalleeMethodObjectAddr(callee_method_idx, invoke_type,
                                                this_addr, dex_pc, is_fast_path);
 
-    if (!is_static && !(opt_flags & MIR_IGNORE_NULL_CHECK)) {
-      EmitGuard_NullPointerException(dex_pc, this_addr);
+    if (!is_static) {
+      EmitGuard_NullPointerException(dex_pc, this_addr, opt_flags);
     }
   } else {
-    if (!is_static && !(opt_flags & MIR_IGNORE_NULL_CHECK)) {
-      EmitGuard_NullPointerException(dex_pc, this_addr);
+    if (!is_static) {
+      EmitGuard_NullPointerException(dex_pc, this_addr, opt_flags);
     }
 
     switch (invoke_type) {
@@ -2196,9 +2183,7 @@
   llvm::Value* array_addr = call_inst.getArgOperand(1);
   int opt_flags = LV2UInt(call_inst.getArgOperand(0));
 
-  if (!(opt_flags & MIR_IGNORE_NULL_CHECK)) {
-    EmitGuard_NullPointerException(dex_pc, array_addr);
-  }
+  EmitGuard_NullPointerException(dex_pc, array_addr, opt_flags);
 
   // Get the array length and store it to the register
   return EmitLoadArrayLength(array_addr);
@@ -2284,7 +2269,7 @@
     // When the number of the elements in the payload is zero, we don't have
     // to copy any numbers.  However, we should check whether the array object
     // address is equal to null or not.
-    EmitGuard_NullPointerException(dex_pc, array_addr);
+    EmitGuard_NullPointerException(dex_pc, array_addr, 0);
   } else {
     // To save the code size, we are going to call the runtime function to
     // copy the content from DexFile.
@@ -2443,49 +2428,89 @@
 }
 
 void GBCExpanderPass::EmitGuard_NullPointerException(uint32_t dex_pc,
-                                                     llvm::Value* object) {
-  llvm::Value* equal_null = irb_.CreateICmpEQ(object, irb_.getJNull());
+                                                     llvm::Value* object,
+                                                     int opt_flags) {
+  bool ignore_null_check = ((opt_flags & MIR_IGNORE_NULL_CHECK) != 0);
+  if (ignore_null_check) {
+    llvm::BasicBlock* lpad = GetLandingPadBasicBlock(dex_pc);
+    if (lpad) {
+      // There is at least one catch: create a "fake" conditional branch to
+      // keep the exception edge to the catch block.
+      landing_pad_phi_mapping_[lpad].push_back(
+          std::make_pair(current_bb_->getUniquePredecessor(),
+                         irb_.GetInsertBlock()));
 
-  llvm::BasicBlock* block_exception =
-    CreateBasicBlockWithDexPC(dex_pc, "nullp");
+      llvm::BasicBlock* block_continue =
+          CreateBasicBlockWithDexPC(dex_pc, "cont");
 
-  llvm::BasicBlock* block_continue =
-    CreateBasicBlockWithDexPC(dex_pc, "cont");
+      irb_.CreateCondBr(irb_.getFalse(), lpad, block_continue);
 
-  irb_.CreateCondBr(equal_null, block_exception, block_continue, kUnlikely);
+      irb_.SetInsertPoint(block_continue);
+    }
+  } else {
+    llvm::Value* equal_null = irb_.CreateICmpEQ(object, irb_.getJNull());
 
-  irb_.SetInsertPoint(block_exception);
-  EmitUpdateDexPC(dex_pc);
-  irb_.CreateCall(irb_.GetRuntime(runtime_support::ThrowNullPointerException),
-                  irb_.getInt32(dex_pc));
-  EmitBranchExceptionLandingPad(dex_pc);
+    llvm::BasicBlock* block_exception =
+        CreateBasicBlockWithDexPC(dex_pc, "nullp");
 
-  irb_.SetInsertPoint(block_continue);
+    llvm::BasicBlock* block_continue =
+        CreateBasicBlockWithDexPC(dex_pc, "cont");
+
+    irb_.CreateCondBr(equal_null, block_exception, block_continue, kUnlikely);
+
+    irb_.SetInsertPoint(block_exception);
+    EmitUpdateDexPC(dex_pc);
+    irb_.CreateCall(irb_.GetRuntime(runtime_support::ThrowNullPointerException),
+                    irb_.getInt32(dex_pc));
+    EmitBranchExceptionLandingPad(dex_pc);
+
+    irb_.SetInsertPoint(block_continue);
+  }
 }
 
 void
 GBCExpanderPass::EmitGuard_ArrayIndexOutOfBoundsException(uint32_t dex_pc,
                                                           llvm::Value* array,
-                                                          llvm::Value* index) {
-  llvm::Value* array_len = EmitLoadArrayLength(array);
+                                                          llvm::Value* index,
+                                                          int opt_flags) {
+  bool ignore_range_check = ((opt_flags & MIR_IGNORE_RANGE_CHECK) != 0);
+  if (ignore_range_check) {
+    llvm::BasicBlock* lpad = GetLandingPadBasicBlock(dex_pc);
+    if (lpad) {
+      // There is at least one catch: create a "fake" conditional branch to
+      // keep the exception edge to the catch block.
+      landing_pad_phi_mapping_[lpad].push_back(
+          std::make_pair(current_bb_->getUniquePredecessor(),
+                         irb_.GetInsertBlock()));
 
-  llvm::Value* cmp = irb_.CreateICmpUGE(index, array_len);
+      llvm::BasicBlock* block_continue =
+          CreateBasicBlockWithDexPC(dex_pc, "cont");
 
-  llvm::BasicBlock* block_exception =
-    CreateBasicBlockWithDexPC(dex_pc, "overflow");
+      irb_.CreateCondBr(irb_.getFalse(), lpad, block_continue);
 
-  llvm::BasicBlock* block_continue =
-    CreateBasicBlockWithDexPC(dex_pc, "cont");
+      irb_.SetInsertPoint(block_continue);
+    }
+  } else {
+    llvm::Value* array_len = EmitLoadArrayLength(array);
 
-  irb_.CreateCondBr(cmp, block_exception, block_continue, kUnlikely);
+    llvm::Value* cmp = irb_.CreateICmpUGE(index, array_len);
 
-  irb_.SetInsertPoint(block_exception);
+    llvm::BasicBlock* block_exception =
+        CreateBasicBlockWithDexPC(dex_pc, "overflow");
 
-  EmitUpdateDexPC(dex_pc);
-  irb_.CreateCall2(irb_.GetRuntime(runtime_support::ThrowIndexOutOfBounds), index, array_len);
-  EmitBranchExceptionLandingPad(dex_pc);
+    llvm::BasicBlock* block_continue =
+        CreateBasicBlockWithDexPC(dex_pc, "cont");
 
-  irb_.SetInsertPoint(block_continue);
+    irb_.CreateCondBr(cmp, block_exception, block_continue, kUnlikely);
+
+    irb_.SetInsertPoint(block_exception);
+
+    EmitUpdateDexPC(dex_pc);
+    irb_.CreateCall2(irb_.GetRuntime(runtime_support::ThrowIndexOutOfBounds), index, array_len);
+    EmitBranchExceptionLandingPad(dex_pc);
+
+    irb_.SetInsertPoint(block_continue);
+  }
 }
 
 llvm::FunctionType* GBCExpanderPass::GetFunctionType(uint32_t method_idx,