Merge "Fix heap bitmap rounding down size error" into ics-mr1-plus-art
diff --git a/src/compiler/Compiler.h b/src/compiler/Compiler.h
index 4d749ce..088768b 100644
--- a/src/compiler/Compiler.h
+++ b/src/compiler/Compiler.h
@@ -197,6 +197,7 @@
 bool oatIsFpReg(int reg);
 uint32_t oatFpRegMask(void);
 void oatReplaceSpecialChars(std::string& str);
+BasicBlock* oatFindBlock(CompilationUnit* cUnit, unsigned int codeOffset);
 
 }  // namespace art
 
diff --git a/src/compiler/Frontend.cc b/src/compiler/Frontend.cc
index b714065..9fa6911 100644
--- a/src/compiler/Frontend.cc
+++ b/src/compiler/Frontend.cc
@@ -246,6 +246,12 @@
   return bb;
 }
 
+/* Find existing block */
+BasicBlock* oatFindBlock(CompilationUnit* cUnit, unsigned int codeOffset)
+{
+  return findBlock(cUnit, codeOffset, false, false, NULL);
+}
+
 /* Turn method name into a legal Linux file name */
 void oatReplaceSpecialChars(std::string& str)
 {
@@ -781,7 +787,7 @@
       || (PrettyMethod(method_idx, dex_file).find("FloatMath") != std::string::npos)
       || (PrettyMethod(method_idx, dex_file).find("Goto") != std::string::npos)
       || (PrettyMethod(method_idx, dex_file).find("InternedString") != std::string::npos)
-   //   || (PrettyMethod(method_idx, dex_file).find("IntMath") != std::string::npos)
+      || (PrettyMethod(method_idx, dex_file).find("IntMath") != std::string::npos)
       || (PrettyMethod(method_idx, dex_file).find("InstField") != std::string::npos)
       || (PrettyMethod(method_idx, dex_file).find("MethodCall") != std::string::npos)
       || (PrettyMethod(method_idx, dex_file).find("Monitor") != std::string::npos)
diff --git a/src/compiler/codegen/MethodBitcode.cc b/src/compiler/codegen/MethodBitcode.cc
index a4521bb..71921d0 100644
--- a/src/compiler/codegen/MethodBitcode.cc
+++ b/src/compiler/codegen/MethodBitcode.cc
@@ -140,6 +140,38 @@
   return GET_ELEM_N(cUnit->ssaStrings, char*, ssaReg);
 }
 
+llvm::BasicBlock* findCaseTarget(CompilationUnit* cUnit, uint32_t vaddr)
+{
+  BasicBlock* bb = oatFindBlock(cUnit, vaddr);
+  DCHECK(bb != NULL);
+  return getLLVMBlock(cUnit, bb->id);
+}
+
+void convertPackedSwitch(CompilationUnit* cUnit, BasicBlock* bb,
+                         int32_t tableOffset, RegLocation rlSrc)
+{
+  const Instruction::PackedSwitchPayload* payload =
+      reinterpret_cast<const Instruction::PackedSwitchPayload*>(
+      cUnit->insns + cUnit->currentDalvikOffset + tableOffset);
+
+  llvm::Value* value = getLLVMValue(cUnit, rlSrc.origSReg);
+
+  llvm::SwitchInst* sw =
+    cUnit->irb->CreateSwitch(value, getLLVMBlock(cUnit, bb->fallThrough->id),
+                             payload->case_count);
+
+  for (uint16_t i = 0; i < payload->case_count; ++i) {
+    llvm::BasicBlock* llvmBB =
+        findCaseTarget(cUnit, cUnit->currentDalvikOffset + payload->targets[i]);
+    sw->addCase(cUnit->irb->getInt32(payload->first_key + i), llvmBB);
+  }
+  llvm::MDNode* switchNode =
+      llvm::MDNode::get(*cUnit->context, cUnit->irb->getInt32(tableOffset));
+  sw->setMetadata("SwitchTable", switchNode);
+  bb->taken = NULL;
+  bb->fallThrough = NULL;
+}
+
 void convertSget(CompilationUnit* cUnit, int32_t fieldIndex,
                  greenland::IntrinsicHelper::IntrinsicId id,
                  RegLocation rlDest)
@@ -1501,11 +1533,12 @@
                             rlDest, rlSrc[0], rlSrc[1]);
       break;
 
-#if 0
     case Instruction::PACKED_SWITCH:
-      genPackedSwitch(cUnit, vB, rlSrc[0]);
+      convertPackedSwitch(cUnit, bb, vB, rlSrc[0]);
       break;
 
+#if 0
+
     case Instruction::SPARSE_SWITCH:
       genSparseSwitch(cUnit, vB, rlSrc[0], labelList);
       break;
@@ -2138,12 +2171,17 @@
 {
   RegLocation rlDest = getLoc(cUnit, inst);
   llvm::Value* lhs = inst->getOperand(0);
-  // Special-case RSUB
+  // Special-case RSUB/NEG
   llvm::ConstantInt* lhsImm = llvm::dyn_cast<llvm::ConstantInt>(lhs);
   if ((op == kOpSub) && (lhsImm != NULL)) {
     RegLocation rlSrc1 = getLoc(cUnit, inst->getOperand(1));
-    genArithOpIntLit(cUnit, Instruction::RSUB_INT, rlDest, rlSrc1,
-                     lhsImm->getSExtValue());
+    if (rlSrc1.wide) {
+      DCHECK_EQ(lhsImm->getSExtValue(), 0);
+      genArithOpLong(cUnit, Instruction::NEG_LONG, rlDest, rlSrc1, rlSrc1);
+    } else {
+      genArithOpIntLit(cUnit, Instruction::RSUB_INT, rlDest, rlSrc1,
+                       lhsImm->getSExtValue());
+    }
     return;
   }
   DCHECK(lhsImm == NULL);
@@ -2560,6 +2598,20 @@
   genCmpLong(cUnit, rlDest, rlSrc1, rlSrc2);
 }
 
+void cvtSwitch(CompilationUnit* cUnit, llvm::Instruction* inst)
+{
+  llvm::SwitchInst* swInst = llvm::dyn_cast<llvm::SwitchInst>(inst);
+  DCHECK(swInst != NULL);
+  llvm::Value* testVal = swInst->getCondition();
+  llvm::MDNode* tableOffsetNode = swInst->getMetadata("SwitchTable");
+  DCHECK(tableOffsetNode != NULL);
+  llvm::ConstantInt* tableOffsetValue =
+          static_cast<llvm::ConstantInt*>(tableOffsetNode->getOperand(0));
+  int32_t tableOffset = tableOffsetValue->getSExtValue();
+  RegLocation rlSrc = getLoc(cUnit, testVal);
+  genPackedSwitch(cUnit, tableOffset, rlSrc);
+}
+
 void cvtInvoke(CompilationUnit* cUnit, llvm::CallInst* callInst,
                bool isVoid, bool isFilledNewArray)
 {
@@ -2999,6 +3051,8 @@
       case llvm::Instruction::SExt: cvtIntExt(cUnit, inst, true /* signed */);
         break;
 
+      case llvm::Instruction::Switch: cvtSwitch(cUnit, inst); break;
+
       case llvm::Instruction::Unreachable:
         break;  // FIXME: can we really ignore these?
 
@@ -3007,7 +3061,6 @@
       case llvm::Instruction::UIToFP:
       case llvm::Instruction::PtrToInt:
       case llvm::Instruction::IntToPtr:
-      case llvm::Instruction::Switch:
       case llvm::Instruction::FCmp:
       case llvm::Instruction::URem:
       case llvm::Instruction::UDiv: