Implement switch instructions.

Change-Id: Ib159690b481e9698274b72d2f8d7e3f363795b75
diff --git a/src/compiler_llvm/method_compiler.cc b/src/compiler_llvm/method_compiler.cc
index 9101c42..ab90803 100644
--- a/src/compiler_llvm/method_compiler.cc
+++ b/src/compiler_llvm/method_compiler.cc
@@ -1296,15 +1296,62 @@
 
 void MethodCompiler::EmitInsn_PackedSwitch(uint32_t dex_pc,
                                            Instruction const* insn) {
-  // UNIMPLEMENTED(WARNING);
-  irb_.CreateUnreachable();
+
+  Instruction::DecodedInstruction dec_insn(insn);
+
+  struct PACKED Payload {
+    uint16_t ident_;
+    uint16_t num_cases_;
+    int32_t first_key_;
+    int32_t targets_[];
+  };
+
+  int32_t payload_offset = static_cast<int32_t>(dex_pc) +
+                           static_cast<int32_t>(dec_insn.vB_);
+
+  Payload const* payload =
+    reinterpret_cast<Payload const*>(code_item_->insns_ + payload_offset);
+
+  llvm::Value* value = EmitLoadDalvikReg(dec_insn.vA_, kInt, kAccurate);
+
+  llvm::SwitchInst* sw =
+    irb_.CreateSwitch(value, GetNextBasicBlock(dex_pc), payload->num_cases_);
+
+  for (uint16_t i = 0; i < payload->num_cases_; ++i) {
+    sw->addCase(irb_.getInt32(payload->first_key_ + i),
+                GetBasicBlock(dex_pc + payload->targets_[i]));
+  }
 }
 
 
 void MethodCompiler::EmitInsn_SparseSwitch(uint32_t dex_pc,
                                            Instruction const* insn) {
-  // UNIMPLEMENTED(WARNING);
-  irb_.CreateUnreachable();
+
+  Instruction::DecodedInstruction dec_insn(insn);
+
+  struct PACKED Payload {
+    uint16_t ident_;
+    uint16_t num_cases_;
+    int32_t keys_and_targets_[];
+  };
+
+  int32_t payload_offset = static_cast<int32_t>(dex_pc) +
+                           static_cast<int32_t>(dec_insn.vB_);
+
+  Payload const* payload =
+    reinterpret_cast<Payload const*>(code_item_->insns_ + payload_offset);
+
+  int32_t const* keys = payload->keys_and_targets_;
+  int32_t const* targets = payload->keys_and_targets_ + payload->num_cases_;
+
+  llvm::Value* value = EmitLoadDalvikReg(dec_insn.vA_, kInt, kAccurate);
+
+  llvm::SwitchInst* sw =
+    irb_.CreateSwitch(value, GetNextBasicBlock(dex_pc), payload->num_cases_);
+
+  for (size_t i = 0; i < payload->num_cases_; ++i) {
+    sw->addCase(irb_.getInt32(keys[i]), GetBasicBlock(dex_pc + targets[i]));
+  }
 }