Quick compiler: complete switch support

With this CL, all Dex opcodes are handled.  We pass 79 run-tests,
and fail 12.  Temporarily going single-threaded for the Quick
compiler (llvm's ir-builder dies otherwise - will figure out what I
need to do for multi-threaded operation in a later CL).

Change-Id: I389e94d9a831096d4e7493460729933fb45e649e
diff --git a/src/compiler/CompilerIR.h b/src/compiler/CompilerIR.h
index ef56876..7420bda 100644
--- a/src/compiler/CompilerIR.h
+++ b/src/compiler/CompilerIR.h
@@ -533,7 +533,7 @@
   ArenaBitVector* tempSSARegisterV;   // numSSARegs
   int* tempSSABlockIdV;               // working storage for Phi labels
   bool printSSANames;
-  void* blockLabelList;
+  LIR* blockLabelList;
   bool quitLoopMode;                  // cold path/complex bytecode
   int preservedRegsUsed;              // How many callee save regs used
   /*
diff --git a/src/compiler/Frontend.cc b/src/compiler/Frontend.cc
index 9fa6911..aeee4f0 100644
--- a/src/compiler/Frontend.cc
+++ b/src/compiler/Frontend.cc
@@ -763,45 +763,7 @@
   cUnit->numRegs = code_item->registers_size_ - cUnit->numIns;
   cUnit->numOuts = code_item->outs_size_;
 #if defined(ART_USE_QUICK_COMPILER)
-  // TODO: remove - temp for Quick compiler bring-up
-  if ((PrettyMethod(method_idx, dex_file).find("fibonacci") != std::string::npos)
-      || (PrettyMethod(method_idx, dex_file).find("HelloWorld") != std::string::npos)
-      || (PrettyMethod(method_idx, dex_file).find("count10_006") != std::string::npos)
-      || (PrettyMethod(method_idx, dex_file).find("exceptions_007") != std::string::npos)
-      || (PrettyMethod(method_idx, dex_file).find("catchAndRethrow") != std::string::npos)
-      || (PrettyMethod(method_idx, dex_file).find("math_012") != std::string::npos)
-      || (PrettyMethod(method_idx, dex_file).find("math_013") != std::string::npos)
-      || (PrettyMethod(method_idx, dex_file).find("math_014") != std::string::npos)
-      || (PrettyMethod(method_idx, dex_file).find("float_017") != std::string::npos)
-      || (PrettyMethod(method_idx, dex_file).find("array_028") != std::string::npos)
-      || (PrettyMethod(method_idx, dex_file).find("writeArray") != std::string::npos)
-      || (PrettyMethod(method_idx, dex_file).find("writeTest") != std::string::npos)
-      || (PrettyMethod(method_idx, dex_file).find("copyTest") != std::string::npos)
-      || (PrettyMethod(method_idx, dex_file).find("shiftTest1") != std::string::npos)
-      || (PrettyMethod(method_idx, dex_file).find("shiftTest2") != std::string::npos)
-      || (PrettyMethod(method_idx, dex_file).find("unsignedShiftTest") != std::string::npos)
-      || (PrettyMethod(method_idx, dex_file).find("convTest") != std::string::npos)
-      || (PrettyMethod(method_idx, dex_file).find("Array") != std::string::npos)
-      || (PrettyMethod(method_idx, dex_file).find("Classes") != std::string::npos)
-      || (PrettyMethod(method_idx, dex_file).find("Compare") != std::string::npos)
-      || (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("InstField") != std::string::npos)
-      || (PrettyMethod(method_idx, dex_file).find("MethodCall") != std::string::npos)
-      || (PrettyMethod(method_idx, dex_file).find("Monitor") != std::string::npos)
-      || (PrettyMethod(method_idx, dex_file).find("StaticField") != std::string::npos)
-   //   || (PrettyMethod(method_idx, dex_file).find("Switch") != std::string::npos)
-   //   || (PrettyMethod(method_idx, dex_file).find("Throw.rethrow") != std::string::npos)
-      || (PrettyMethod(method_idx, dex_file).find("UnresClass") != std::string::npos)
-      || (PrettyMethod(method_idx, dex_file).find("UsresClassSubclass") != std::string::npos)
-      || (PrettyMethod(method_idx, dex_file).find("UsresStuff") != std::string::npos)
-      || (PrettyMethod(method_idx, dex_file).find("UsresTest1") != std::string::npos)
-      || (PrettyMethod(method_idx, dex_file).find("UsresTest2") != std::string::npos)
-     ) {
-    cUnit->genBitcode = true;
-  }
+  cUnit->genBitcode = true;
 #endif
   /* Adjust this value accordingly once inlining is performed */
   cUnit->numDalvikRegisters = code_item->registers_size_;
diff --git a/src/compiler/codegen/MethodBitcode.cc b/src/compiler/codegen/MethodBitcode.cc
index 71921d0..cf7b6ff 100644
--- a/src/compiler/codegen/MethodBitcode.cc
+++ b/src/compiler/codegen/MethodBitcode.cc
@@ -172,6 +172,34 @@
   bb->fallThrough = NULL;
 }
 
+void convertSparseSwitch(CompilationUnit* cUnit, BasicBlock* bb,
+                         int32_t tableOffset, RegLocation rlSrc)
+{
+  const Instruction::SparseSwitchPayload* payload =
+      reinterpret_cast<const Instruction::SparseSwitchPayload*>(
+      cUnit->insns + cUnit->currentDalvikOffset + tableOffset);
+
+  const int32_t* keys = payload->GetKeys();
+  const int32_t* targets = payload->GetTargets();
+
+  llvm::Value* value = getLLVMValue(cUnit, rlSrc.origSReg);
+
+  llvm::SwitchInst* sw =
+    cUnit->irb->CreateSwitch(value, getLLVMBlock(cUnit, bb->fallThrough->id),
+                             payload->case_count);
+
+  for (size_t i = 0; i < payload->case_count; ++i) {
+    llvm::BasicBlock* llvmBB =
+        findCaseTarget(cUnit, cUnit->currentDalvikOffset + targets[i]);
+    sw->addCase(cUnit->irb->getInt32(keys[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)
@@ -301,7 +329,7 @@
 void convertThrowVerificationError(CompilationUnit* cUnit, int info1, int info2)
 {
   llvm::Function* func = cUnit->intrinsic_helper->GetIntrinsicFunction(
-      greenland::IntrinsicHelper::Throw);
+      greenland::IntrinsicHelper::ThrowVerificationError);
   llvm::SmallVector<llvm::Value*, 2> args;
   args.push_back(cUnit->irb->getInt32(info1));
   args.push_back(cUnit->irb->getInt32(info2));
@@ -1537,12 +1565,9 @@
       convertPackedSwitch(cUnit, bb, vB, rlSrc[0]);
       break;
 
-#if 0
-
     case Instruction::SPARSE_SWITCH:
-      genSparseSwitch(cUnit, vB, rlSrc[0], labelList);
+      convertSparseSwitch(cUnit, bb, vB, rlSrc[0]);
       break;
-#endif
 
     default:
       UNIMPLEMENTED(FATAL) << "Unsupported Dex opcode 0x" << std::hex << opcode;
@@ -2609,7 +2634,14 @@
           static_cast<llvm::ConstantInt*>(tableOffsetNode->getOperand(0));
   int32_t tableOffset = tableOffsetValue->getSExtValue();
   RegLocation rlSrc = getLoc(cUnit, testVal);
-  genPackedSwitch(cUnit, tableOffset, rlSrc);
+  const u2* table = cUnit->insns + cUnit->currentDalvikOffset + tableOffset;
+  u2 tableMagic = *table;
+  if (tableMagic == 0x100) {
+    genPackedSwitch(cUnit, tableOffset, rlSrc);
+  } else {
+    DCHECK_EQ(tableMagic, 0x200);
+    genSparseSwitch(cUnit, tableOffset, rlSrc);
+  }
 }
 
 void cvtInvoke(CompilationUnit* cUnit, llvm::CallInst* callInst,
@@ -2859,6 +2891,9 @@
             case greenland::IntrinsicHelper::HLSputDouble:
               cvtSput(cUnit, callInst, true /* wide */, false /* Object */);
               break;
+            case greenland::IntrinsicHelper::HLSputObject:
+              cvtSput(cUnit, callInst, false /* wide */, true /* Object */);
+              break;
             case greenland::IntrinsicHelper::GetException:
               cvtMoveException(cUnit, callInst);
               break;
@@ -3117,8 +3152,8 @@
   int numBasicBlocks = func->getBasicBlockList().size();
   // Allocate a list for LIR basic block labels
   cUnit->blockLabelList =
-    (void*)oatNew(cUnit, sizeof(LIR) * numBasicBlocks, true, kAllocLIR);
-  LIR* labelList = (LIR*)cUnit->blockLabelList;
+    (LIR*)oatNew(cUnit, sizeof(LIR) * numBasicBlocks, true, kAllocLIR);
+  LIR* labelList = cUnit->blockLabelList;
   int nextLabel = 0;
   for (llvm::Function::iterator i = func->begin(),
        e = func->end(); i != e; ++i) {
diff --git a/src/compiler/codegen/MethodCodegenDriver.cc b/src/compiler/codegen/MethodCodegenDriver.cc
index 62939ba..d49b329 100644
--- a/src/compiler/codegen/MethodCodegenDriver.cc
+++ b/src/compiler/codegen/MethodCodegenDriver.cc
@@ -447,7 +447,7 @@
       break;
 
     case Instruction::SPARSE_SWITCH:
-      genSparseSwitch(cUnit, vB, rlSrc[0], labelList);
+      genSparseSwitch(cUnit, vB, rlSrc[0]);
       break;
 
     case Instruction::CMPL_FLOAT:
@@ -878,7 +878,7 @@
 bool methodBlockCodeGen(CompilationUnit* cUnit, BasicBlock* bb)
 {
   MIR* mir;
-  LIR* labelList = (LIR*) cUnit->blockLabelList;
+  LIR* labelList = cUnit->blockLabelList;
   int blockId = bb->id;
 
   cUnit->curBlock = bb;
@@ -992,7 +992,7 @@
 /* Set basic block labels */
 bool labelBlocks(CompilationUnit* cUnit, BasicBlock* bb)
 {
-  LIR* labelList = (LIR*) cUnit->blockLabelList;
+  LIR* labelList = cUnit->blockLabelList;
   int blockId = bb->id;
 
   cUnit->curBlock = bb;
@@ -1037,7 +1037,7 @@
 {
   /* Used to hold the labels of each block */
   cUnit->blockLabelList =
-      (void *) oatNew(cUnit, sizeof(LIR) * cUnit->numBlocks, true, kAllocLIR);
+      (LIR*) oatNew(cUnit, sizeof(LIR) * cUnit->numBlocks, true, kAllocLIR);
 
   oatDataFlowAnalysisDispatcher(cUnit, methodBlockCodeGen,
                                 kPreOrderDFSTraversal, false /* Iterative */);
diff --git a/src/compiler/codegen/arm/FP/Thumb2VFP.cc b/src/compiler/codegen/arm/FP/Thumb2VFP.cc
index 1b67ecb..3ea28c9 100644
--- a/src/compiler/codegen/arm/FP/Thumb2VFP.cc
+++ b/src/compiler/codegen/arm/FP/Thumb2VFP.cc
@@ -162,7 +162,7 @@
 void genFusedFPCmpBranch(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir,
                          bool gtBias, bool isDouble)
 {
-  LIR* labelList = (LIR*)cUnit->blockLabelList;
+  LIR* labelList = cUnit->blockLabelList;
   LIR* target = &labelList[bb->taken->id];
   RegLocation rlSrc1;
   RegLocation rlSrc2;
diff --git a/src/compiler/codegen/arm/Thumb2/Gen.cc b/src/compiler/codegen/arm/Thumb2/Gen.cc
index 579aa43..d2532b7 100644
--- a/src/compiler/codegen/arm/Thumb2/Gen.cc
+++ b/src/compiler/codegen/arm/Thumb2/Gen.cc
@@ -369,7 +369,7 @@
  *   cbnz  rIdx, lp
  */
 void genSparseSwitch(CompilationUnit* cUnit, uint32_t tableOffset,
-                     RegLocation rlSrc, LIR* labelList)
+                     RegLocation rlSrc)
 {
   const u2* table = cUnit->insns + cUnit->currentDalvikOffset + tableOffset;
   if (cUnit->printMe) {
@@ -654,7 +654,7 @@
 
 void genFusedLongCmpBranch(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir)
 {
-  LIR* labelList = (LIR*)cUnit->blockLabelList;
+  LIR* labelList = cUnit->blockLabelList;
   LIR* taken = &labelList[bb->taken->id];
   LIR* notTaken = &labelList[bb->fallThrough->id];
   RegLocation rlSrc1 = oatGetSrcWide(cUnit, mir, 0);
diff --git a/src/compiler/codegen/mips/Mips32/Gen.cc b/src/compiler/codegen/mips/Mips32/Gen.cc
index 090c086..7712985 100644
--- a/src/compiler/codegen/mips/Mips32/Gen.cc
+++ b/src/compiler/codegen/mips/Mips32/Gen.cc
@@ -64,7 +64,7 @@
  *
  */
 void genSparseSwitch(CompilationUnit* cUnit, uint32_t tableOffset,
-                     RegLocation rlSrc, LIR* labelList)
+                     RegLocation rlSrc)
 {
   const u2* table = cUnit->insns + cUnit->currentDalvikOffset + tableOffset;
   if (cUnit->printMe) {
diff --git a/src/compiler/codegen/x86/X86/Gen.cc b/src/compiler/codegen/x86/X86/Gen.cc
index f5466ee..b0b6ba8 100644
--- a/src/compiler/codegen/x86/X86/Gen.cc
+++ b/src/compiler/codegen/x86/X86/Gen.cc
@@ -52,7 +52,7 @@
 BasicBlock *findBlock(CompilationUnit* cUnit, unsigned int codeOffset,
                       bool split, bool create, BasicBlock** immedPredBlockP);
 void genSparseSwitch(CompilationUnit* cUnit, uint32_t tableOffset,
-                     RegLocation rlSrc, LIR* labelList)
+                     RegLocation rlSrc)
 {
   const u2* table = cUnit->insns + cUnit->currentDalvikOffset + tableOffset;
   if (cUnit->printMe) {
@@ -67,6 +67,7 @@
     BasicBlock* case_block = findBlock(cUnit,
                                        cUnit->currentDalvikOffset + targets[i],
                                        false, false, NULL);
+    LIR* labelList = cUnit->blockLabelList;
     opCmpImmBranch(cUnit, kCondEq, rlSrc.lowReg, key,
                    &labelList[case_block->id]);
   }
diff --git a/src/dex2oat.cc b/src/dex2oat.cc
index f2c73e9..4587b30 100644
--- a/src/dex2oat.cc
+++ b/src/dex2oat.cc
@@ -473,7 +473,11 @@
   uintptr_t image_base = 0;
   UniquePtr<std::string> host_prefix;
   std::vector<const char*> runtime_args;
+#if defined(ART_USE_QUICK_COMPILER)
+  int thread_count = 1;
+#else
   int thread_count = sysconf(_SC_NPROCESSORS_CONF);
+#endif
   bool support_debugging = false;
 #if defined(__arm__)
   InstructionSet instruction_set = kThumb2;