Implement ARM32 switch lowering.

A naive implementation of switch lowering using sequential tests for each of the cases.

BUG= none
TEST=switch-opt.ll
R=jvoung@chromium.org

Review URL: https://codereview.chromium.org/1213593002.
diff --git a/src/IceTargetLoweringARM32.cpp b/src/IceTargetLoweringARM32.cpp
index 4797683..b1081b3 100644
--- a/src/IceTargetLoweringARM32.cpp
+++ b/src/IceTargetLoweringARM32.cpp
@@ -2037,8 +2037,36 @@
 }
 
 void TargetARM32::lowerSwitch(const InstSwitch *Inst) {
-  (void)Inst;
-  UnimplementedError(Func->getContext()->getFlags());
+  // This implements the most naive possible lowering.
+  // cmp a,val[0]; jeq label[0]; cmp a,val[1]; jeq label[1]; ... jmp default
+  Operand *Src0 = Inst->getComparison();
+  SizeT NumCases = Inst->getNumCases();
+  if (Src0->getType() == IceType_i64) {
+    // TODO(jvoung): handle and test undef for Src0
+    Variable *Src0Lo = legalizeToVar(loOperand(Src0));
+    Variable *Src0Hi = legalizeToVar(hiOperand(Src0));
+    for (SizeT I = 0; I < NumCases; ++I) {
+      Operand *ValueLo = Ctx->getConstantInt32(Inst->getValue(I));
+      Operand *ValueHi = Ctx->getConstantInt32(Inst->getValue(I) >> 32);
+      ValueLo = legalize(ValueLo, Legal_Reg | Legal_Flex);
+      ValueHi = legalize(ValueHi, Legal_Reg | Legal_Flex);
+      _cmp(Src0Lo, ValueLo);
+      _cmp(Src0Hi, ValueHi, CondARM32::EQ);
+      _br(Inst->getLabel(I), CondARM32::EQ);
+    }
+    _br(Inst->getLabelDefault());
+    return;
+  }
+ 
+  // 32 bit integer
+  Variable *Src0Var = legalizeToVar(Src0);
+  for (SizeT I = 0; I < NumCases; ++I) {
+    Operand *Value = Ctx->getConstantInt32(Inst->getValue(I));
+    Value = legalize(Value, Legal_Reg | Legal_Flex);
+    _cmp(Src0Var, Value);
+    _br(Inst->getLabel(I), CondARM32::EQ);
+  }
+  _br(Inst->getLabelDefault());
 }
 
 void TargetARM32::lowerUnreachable(const InstUnreachable * /*Inst*/) {
diff --git a/src/IceTargetLoweringARM32.h b/src/IceTargetLoweringARM32.h
index fdb025f..1691d6c 100644
--- a/src/IceTargetLoweringARM32.h
+++ b/src/IceTargetLoweringARM32.h
@@ -183,6 +183,9 @@
   void _br(CfgNode *Target) {
     Context.insert(InstARM32Br::create(Func, Target));
   }
+  void _br(CfgNode *Target, CondARM32::Cond Condition) {
+    Context.insert(InstARM32Br::create(Func, Target, Condition));
+  }
   void _cmp(Variable *Src0, Operand *Src1,
             CondARM32::Cond Pred = CondARM32::AL) {
     Context.insert(InstARM32Cmp::create(Func, Src0, Src1, Pred));
diff --git a/tests_lit/llvm2ice_tests/switch-opt.ll b/tests_lit/llvm2ice_tests/switch-opt.ll
index 1fbe064..ed6b8b7 100644
--- a/tests_lit/llvm2ice_tests/switch-opt.ll
+++ b/tests_lit/llvm2ice_tests/switch-opt.ll
@@ -4,6 +4,11 @@
 
 ; RUN: %p2i -i %s --filetype=obj --disassemble --args -O2 | FileCheck %s
 
+; TODO(jvoung): Update to -02 once the phi assignments is done for ARM
+; RUN: %if --need=target_ARM32 --command %p2i --filetype=asm --assemble \
+; RUN:   --disassemble --target arm32 -i %s --args -Om1 --skip-unimplemented \
+; RUN:   | %if --need=target_ARM32 --command FileCheck --check-prefix ARM32 %s
+
 define i32 @testSwitch(i32 %a) {
 entry:
   switch i32 %a, label %sw.default [
@@ -49,6 +54,11 @@
 ; CHECK-LABEL: testSwitchImm
 ; CHECK-NOT: cmp 0x{{[0-9a-f]*}},
 
+; ARM32-LABEL: testSwitchImm
+; ARM32: cmp {{r[0-9]+}}, #1
+; ARM32-NEXT: beq
+; ARM32-NEXT: b
+
 ; Test for correct 64-bit lowering.
 define internal i32 @testSwitch64(i64 %a) {
 entry:
@@ -93,6 +103,24 @@
 ; CHECK-NEXT: cmp {{.*}},0x12
 ; CHECK-NEXT: je
 
+; ARM32-LABEL: testSwitch64
+; ARM32: cmp {{r[0-9]+}}, #123
+; ARM32-NEXT: cmpeq {{r[0-9]+}}, #0
+; ARM32-NEXT: beq
+; ARM32: cmp {{r[0-9]+}}, #234
+; ARM32-NEXT: cmpeq {{r[0-9]+}}, #0
+; ARM32-NEXT: beq
+; ARM32: movw [[REG:r[0-9]+]], #345
+; ARM32-NEXT: cmp {{r[0-9]+}}, [[REG]]
+; ARM32-NEXT: cmpeq {{r[0-9]+}}, #0
+; ARM32-NEXT: beq
+; ARM32: movw [[REG:r[0-9]+]], #30864
+; ARM32-NEXT: movt [[REG]], #13398
+; ARM32-NEXT: cmp {{r[0-9]+}}, [[REG]]
+; ARM32-NEXT: cmpeq {{r[0-9]+}}, #18
+; ARM32-NEXT: beq
+; ARM32-NEXT: b
+
 ; Similar to testSwitchImm, make sure proper addressing modes are
 ; used.  In reality, this is tested by running the output through the
 ; assembler.
@@ -110,3 +138,10 @@
 ; CHECK-NEXT: jne
 ; CHECK-NEXT: cmp {{.*}},0x0
 ; CHECK-NEXT: je
+
+; ARM32-LABEL: testSwitchImm64
+; ARM32: cmp {{r[0-9]+}}, #1
+; ARM32-NEXT: cmpeq {{r[0-9]+}}, #0
+; ARM32-NEXT: beq [[ADDR:[0-9a-f]+]]
+; ARM32-NEXT: b [[ADDR]]
+