ARM: lowerSelect for integers.

No bool-folding optimization, just the straightforward
compare followed by mov and conditional mov.

BUG= https://code.google.com/p/nativeclient/issues/detail?id=4076
R=stichnot@chromium.org

Review URL: https://codereview.chromium.org/1211243005.
diff --git a/src/IceConditionCodesX8664.h b/src/IceConditionCodesX8664.h
index 297b54b..59a1493 100644
--- a/src/IceConditionCodesX8664.h
+++ b/src/IceConditionCodesX8664.h
@@ -19,14 +19,14 @@
 
 namespace Ice {
 
-namespace CondX8664  {
+namespace CondX8664 {
 // An enum of condition codes used for branches and cmov. The enum value
 // should match the value used to encode operands in binary instructions.
 enum BrCond {
 #define X(tag, encode, opp, dump, emit) tag encode,
-    ICEINSTX8664BR_TABLE
+  ICEINSTX8664BR_TABLE
 #undef X
-    Br_None
+      Br_None
 };
 
 // An enum of condition codes relevant to the CMPPS instruction. The enum
@@ -34,9 +34,9 @@
 // instructions.
 enum CmppsCond {
 #define X(tag, emit) tag,
-    ICEINSTX8664CMPPS_TABLE
+  ICEINSTX8664CMPPS_TABLE
 #undef X
-    Cmpps_Invalid
+      Cmpps_Invalid
 };
 
 } // end of namespace CondX8664
diff --git a/src/IceGlobalContext.cpp b/src/IceGlobalContext.cpp
index 450fbba..3473b8c 100644
--- a/src/IceGlobalContext.cpp
+++ b/src/IceGlobalContext.cpp
@@ -31,8 +31,8 @@
 #pragma clang diagnostic pop
 
 #include <algorithm> // max()
-#include <cctype> // isdigit(), isupper()
-#include <locale>  // locale
+#include <cctype>    // isdigit(), isupper()
+#include <locale>    // locale
 #include <unordered_map>
 
 namespace std {
diff --git a/src/IceTargetLowering.cpp b/src/IceTargetLowering.cpp
index 25e013b..33a914d 100644
--- a/src/IceTargetLowering.cpp
+++ b/src/IceTargetLowering.cpp
@@ -519,8 +519,9 @@
          Var.getInitializers()) {
       switch (Init->getKind()) {
       case VariableDeclaration::Initializer::DataInitializerKind: {
-        const auto &Data = llvm::cast<VariableDeclaration::DataInitializer>(
-                               Init.get())->getContents();
+        const auto &Data =
+            llvm::cast<VariableDeclaration::DataInitializer>(Init.get())
+                ->getContents();
         for (SizeT i = 0; i < Init->getNumBytes(); ++i) {
           Str << "\t.byte\t" << (((unsigned)Data[i]) & 0xff) << "\n";
         }
diff --git a/src/IceTargetLoweringARM32.cpp b/src/IceTargetLoweringARM32.cpp
index b1081b3..fad9bcf 100644
--- a/src/IceTargetLoweringARM32.cpp
+++ b/src/IceTargetLoweringARM32.cpp
@@ -2009,8 +2009,51 @@
 }
 
 void TargetARM32::lowerSelect(const InstSelect *Inst) {
-  (void)Inst;
-  UnimplementedError(Func->getContext()->getFlags());
+  Variable *Dest = Inst->getDest();
+  Type DestTy = Dest->getType();
+  Operand *SrcT = Inst->getTrueOperand();
+  Operand *SrcF = Inst->getFalseOperand();
+  Operand *Condition = Inst->getCondition();
+
+  if (isVectorType(DestTy)) {
+    UnimplementedError(Func->getContext()->getFlags());
+    return;
+  }
+  if (isFloatingType(DestTy)) {
+    UnimplementedError(Func->getContext()->getFlags());
+    return;
+  }
+  // TODO(jvoung): handle folding opportunities.
+  // cmp cond, #0; mov t, SrcF; mov_cond t, SrcT; mov dest, t
+  Variable *CmpOpnd0 = legalizeToVar(Condition);
+  Operand *CmpOpnd1 = Ctx->getConstantZero(IceType_i32);
+  _cmp(CmpOpnd0, CmpOpnd1);
+  CondARM32::Cond Cond = CondARM32::NE;
+  if (DestTy == IceType_i64) {
+    // Set the low portion.
+    Variable *DestLo = llvm::cast<Variable>(loOperand(Dest));
+    Variable *TLo = nullptr;
+    Operand *SrcFLo = legalize(loOperand(SrcF), Legal_Reg | Legal_Flex);
+    _mov(TLo, SrcFLo);
+    Operand *SrcTLo = legalize(loOperand(SrcT), Legal_Reg | Legal_Flex);
+    _mov_nonkillable(TLo, SrcTLo, Cond);
+    _mov(DestLo, TLo);
+    // Set the high portion.
+    Variable *DestHi = llvm::cast<Variable>(hiOperand(Dest));
+    Variable *THi = nullptr;
+    Operand *SrcFHi = legalize(hiOperand(SrcF), Legal_Reg | Legal_Flex);
+    _mov(THi, SrcFHi);
+    Operand *SrcTHi = legalize(hiOperand(SrcT), Legal_Reg | Legal_Flex);
+    _mov_nonkillable(THi, SrcTHi, Cond);
+    _mov(DestHi, THi);
+    return;
+  }
+  Variable *T = nullptr;
+  SrcF = legalize(SrcF, Legal_Reg | Legal_Flex);
+  _mov(T, SrcF);
+  SrcT = legalize(SrcT, Legal_Reg | Legal_Flex);
+  _mov_nonkillable(T, SrcT, Cond);
+  _mov(Dest, T);
 }
 
 void TargetARM32::lowerStore(const InstStore *Inst) {
@@ -2057,7 +2100,7 @@
     _br(Inst->getLabelDefault());
     return;
   }
- 
+
   // 32 bit integer
   Variable *Src0Var = legalizeToVar(Src0);
   for (SizeT I = 0; I < NumCases; ++I) {
diff --git a/tests_lit/llvm2ice_tests/64bit.pnacl.ll b/tests_lit/llvm2ice_tests/64bit.pnacl.ll
index d667633..54d8ff0 100644
--- a/tests_lit/llvm2ice_tests/64bit.pnacl.ll
+++ b/tests_lit/llvm2ice_tests/64bit.pnacl.ll
@@ -1580,6 +1580,17 @@
 ; OPTM1: cmp
 ; OPTM1: cmovne
 
+; ARM32-LABEL: select64VarVar
+; The initial compare.
+; ARM32: cmp
+; ARM32: cmpeq
+; ARM32: movcc
+; ARM32: movcs
+; The non-folded compare for the select.
+; ARM32: cmp
+; ARM32: movne
+; ARM32: movne
+
 define internal i64 @select64VarConst(i64 %a, i64 %b) {
 entry:
   %cmp = icmp ult i64 %a, %b
@@ -1604,6 +1615,19 @@
 ; OPTM1: cmp
 ; OPTM1: cmovne
 
+; ARM32-LABEL: select64VarConst
+; ARM32: cmp
+; ARM32: cmpeq
+; ARM32: movcc
+; ARM32: movcs
+; ARM32: cmp
+; ARM32: movw
+; ARM32: movt
+; ARM32: movne
+; ARM32: movw
+; ARM32: movt
+; ARM32: movne
+
 define internal i64 @select64ConstVar(i64 %a, i64 %b) {
 entry:
   %cmp = icmp ult i64 %a, %b
@@ -1628,6 +1652,19 @@
 ; OPTM1: cmp
 ; OPTM1: cmove
 
+; ARM32-LABEL: select64ConstVar
+; ARM32: cmp
+; ARM32: cmpeq
+; ARM32: movcc
+; ARM32: movcs
+; ARM32: cmp
+; ARM32: movw
+; ARM32: movt
+; ARM32: movne
+; ARM32: movw
+; ARM32: movt
+; ARM32: movne
+
 define internal void @icmpEq64Imm() {
 entry:
   %cmp = icmp eq i64 123, 234
diff --git a/tests_lit/llvm2ice_tests/select-opt.ll b/tests_lit/llvm2ice_tests/select-opt.ll
index f6d15bf..a34cec6 100644
--- a/tests_lit/llvm2ice_tests/select-opt.ll
+++ b/tests_lit/llvm2ice_tests/select-opt.ll
@@ -3,8 +3,23 @@
 ; regardless of the optimization level, so there are no special OPTM1
 ; match lines.
 
-; RUN: %p2i -i %s --filetype=obj --disassemble --args -O2 | FileCheck %s
-; RUN: %p2i -i %s --filetype=obj --disassemble --args -Om1 | FileCheck %s
+; RUN: %if --need=target_X8632 --command %p2i --filetype=obj --disassemble \
+; RUN:   --target x8632 -i %s --args -O2 \
+; RUN:   | %if --need=target_X8632 --command FileCheck %s
+; RUN: %if --need=target_X8632 --command %p2i --filetype=obj --disassemble \
+; RUN:   --target x8632 -i %s --args -Om1 \
+; RUN:   | %if --need=target_X8632 --command FileCheck %s
+
+; RUN: %if --need=target_ARM32 --need=allow_dump \
+; RUN:   --command %p2i --filetype=asm --assemble \
+; RUN:   --disassemble --target arm32 -i %s --args -O2 --skip-unimplemented \
+; RUN:   | %if --need=target_ARM32 --need=allow_dump \
+; RUN:   --command FileCheck --check-prefix ARM32 %s
+; RUN: %if --need=target_ARM32 --need=allow_dump \
+; RUN:   --command %p2i --filetype=asm --assemble \
+; RUN:   --disassemble --target arm32 -i %s --args -Om1 --skip-unimplemented \
+; RUN:   | %if --need=target_ARM32 --need=allow_dump \
+; RUN:   --command FileCheck --check-prefix ARM32 %s
 
 define void @testSelect(i32 %a, i32 %b) {
 entry:
@@ -32,6 +47,16 @@
 ; CHECK:      cmp
 ; CHECK:      call {{.*}} R_{{.*}} useInt
 ; CHECK:      ret
+; ARM32-LABEL: testSelect
+; ARM32: cmp
+; ARM32: cmp
+; ARM32: bl {{.*}} useInt
+; ARM32: cmp
+; ARM32: cmp
+; ARM32: mov {{.*}}, #20
+; ARM32: movne {{.*}}, #10
+; ARM32: bl {{.*}} useInt
+; ARM32: bx lr
 
 ; Check for valid addressing mode in the cmp instruction when the
 ; operand is an immediate.
@@ -42,6 +67,8 @@
 }
 ; CHECK-LABEL: testSelectImm32
 ; CHECK-NOT: cmp 0x{{[0-9a-f]+}},
+; ARM32-LABEL: testSelectImm32
+; ARM32-NOT: cmp #{{.*}},
 
 ; Check for valid addressing mode in the cmp instruction when the
 ; operand is an immediate.  There is a different x86-32 lowering
@@ -53,3 +80,5 @@
 }
 ; CHECK-LABEL: testSelectImm64
 ; CHECK-NOT: cmp 0x{{[0-9a-f]+}},
+; ARM32-LABEL: testSelectImm64
+; ARM32-NOT: cmp #{{.*}},