Add new form of ldr/str (immediate) to ARM integrated assembler.

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

Review URL: https://codereview.chromium.org/1431453002 .
diff --git a/src/IceAssemblerARM32.cpp b/src/IceAssemblerARM32.cpp
index 05903e3..4e5549d 100644
--- a/src/IceAssemblerARM32.cpp
+++ b/src/IceAssemblerARM32.cpp
@@ -98,6 +98,10 @@
   return static_cast<IValueT>(Rn);
 }
 
+inline RegARM32::GPRRegister decodeGPRRegister(IValueT R) {
+  return static_cast<RegARM32::GPRRegister>(R);
+}
+
 inline bool isGPRRegisterDefined(RegARM32::GPRRegister R) {
   return R != RegARM32::Encoded_Not_GPR;
 }
@@ -142,7 +146,7 @@
 
 // Returns the GPR register at given Shift in Value.
 inline RegARM32::GPRRegister getGPRReg(IValueT Shift, IValueT Value) {
-  return static_cast<RegARM32::GPRRegister>((Value >> Shift) & 0xF);
+  return decodeGPRRegister((Value >> Shift) & 0xF);
 }
 
 // The way an operand was decoded in functions decodeOperand and decodeAddress
@@ -164,7 +168,7 @@
 // Encodes iiiiitt0mmmm for data-processing (2nd) operands where iiiii=Imm5,
 // tt=Shift, and mmmm=Rm.
 IValueT encodeShiftRotateImm5(IValueT Rm, OperandARM32::ShiftKind Shift,
-                              IValueT imm5) {
+                              IOffsetT imm5) {
   (void)kShiftImmBits;
   assert(imm5 < (1 << kShiftImmBits));
   return (imm5 << kShiftImmShift) | (encodeShift(Shift) << kShiftShift) | Rm;
@@ -212,6 +216,18 @@
                                OperandARM32Mem::Offset);
     return DecodedAsImmRegOffset;
   }
+  if (const auto *Mem = llvm::dyn_cast<OperandARM32Mem>(Opnd)) {
+    if (Mem->isRegReg())
+      // TODO(kschimpf) Add this case.
+      return CantDecode;
+    Variable *Var = Mem->getBase();
+    if (!Var->hasReg())
+      return CantDecode;
+    ConstantInteger32 *Offset = Mem->getOffset();
+    Value = decodeImmRegOffset(decodeGPRRegister(Var->getRegNum()),
+                               Offset->getValue(), Mem->getAddrMode());
+    return DecodedAsImmRegOffset;
+  }
   return CantDecode;
 }
 
diff --git a/src/IceInstARM32.cpp b/src/IceInstARM32.cpp
index f7f9f01..e9a0922 100644
--- a/src/IceInstARM32.cpp
+++ b/src/IceInstARM32.cpp
@@ -857,6 +857,11 @@
   Str << getName(Func) << ":";
 }
 
+template <InstARM32::InstKindARM32 K>
+void InstARM32LoadBase<K>::emitIAS(const Cfg *Func) const {
+  emitUsingTextFixup(Func);
+}
+
 template <> void InstARM32Ldr::emit(const Cfg *Func) const {
   if (!BuildDefs::dump())
     return;
@@ -878,6 +883,20 @@
   getSrc(0)->emit(Func);
 }
 
+template <> void InstARM32Ldr::emitIAS(const Cfg *Func) const {
+  assert(getSrcSize() == 1);
+  Variable *Dest = getDest();
+  Type DestTy = Dest->getType();
+  ARM32::AssemblerARM32 *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
+  if (isVectorType(DestTy) || isScalarFloatingType(DestTy))
+    // TODO(kschimpf) Handle case.
+    Asm->setNeedsTextFixup();
+  else
+    Asm->ldr(Dest, getSrc(0), getPredicate());
+  if (Asm->needsTextFixup())
+    emitUsingTextFixup(Func);
+}
+
 template <> void InstARM32Ldrex::emit(const Cfg *Func) const {
   if (!BuildDefs::dump())
     return;
@@ -1128,6 +1147,19 @@
   getSrc(1)->emit(Func);
 }
 
+void InstARM32Str::emitIAS(const Cfg *Func) const {
+  assert(getSrcSize() == 2);
+  Type Ty = getSrc(0)->getType();
+  ARM32::AssemblerARM32 *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
+  if (isVectorType(Ty) || isScalarFloatingType(Ty))
+    // TODO(kschimpf) Handle case.
+    Asm->setNeedsTextFixup();
+  else
+    Asm->str(getSrc(0), getSrc(1), getPredicate());
+  if (Asm->needsTextFixup())
+    emitUsingTextFixup(Func);
+}
+
 void InstARM32Str::dump(const Cfg *Func) const {
   if (!BuildDefs::dump())
     return;
@@ -1491,6 +1523,9 @@
 template class InstARM32ThreeAddrFP<InstARM32::Vmul>;
 template class InstARM32ThreeAddrFP<InstARM32::Vsub>;
 
+template class InstARM32LoadBase<InstARM32::Ldr>;
+template class InstARM32LoadBase<InstARM32::Ldrex>;
+
 template class InstARM32TwoAddrGPR<InstARM32::Movt>;
 
 template class InstARM32UnaryopGPR<InstARM32::Movw, false>;
diff --git a/src/IceInstARM32.h b/src/IceInstARM32.h
index 0420722..e7d9e4c 100644
--- a/src/IceInstARM32.h
+++ b/src/IceInstARM32.h
@@ -538,6 +538,7 @@
         InstARM32LoadBase(Func, Dest, Source, Predicate);
   }
   void emit(const Cfg *Func) const override;
+  void emitIAS(const Cfg *Func) const override;
   void dump(const Cfg *Func) const override {
     if (!BuildDefs::dump())
       return;
@@ -1008,6 +1009,7 @@
         InstARM32Str(Func, Value, Mem, Predicate);
   }
   void emit(const Cfg *Func) const override;
+  void emitIAS(const Cfg *Func) const override;
   void dump(const Cfg *Func) const override;
   static bool classof(const Inst *Inst) { return isClassof(Inst, Str); }
 
diff --git a/tests_lit/assembler/arm32/global-load-store.ll b/tests_lit/assembler/arm32/global-load-store.ll
index 6c07913..a285e48 100644
--- a/tests_lit/assembler/arm32/global-load-store.ll
+++ b/tests_lit/assembler/arm32/global-load-store.ll
@@ -55,9 +55,12 @@
 
 ; IASM-LABEL:load:
 ; IASM-NEXT: .Lload$__0:
-; IASM-NEXT:    movw    r0, #:lower16:global1   @ .word e3000000
-; IASM-NEXT:    movt    r0, #:upper16:global1   @ .word e3400000
-; IASM-NEXT:    ldr     r0, [r0]
+; IASM-NEXT:    movw    r0, #:lower16:global1
+; IASM-NEXT:    movt    r0, #:upper16:global1
+; IASM-NEXT:    .byte 0x0
+; IASM-NEXT:    .byte 0x0
+; IASM-NEXT:    .byte 0x90
+; IASM-NEXT:    .byte 0xe5
 ; IASM-NEXT:    .byte 0x1e
 ; IASM-NEXT:    .byte 0xff
 ; IASM-NEXT:    .byte 0x2f
@@ -84,9 +87,12 @@
 
 ; IASM-LABEL:store:
 ; IASM-NEXT: .Lstore$__0:
-; IASM-NEXT:    movw    r1, #:lower16:global1   @ .word e3001000
-; IASM-NEXT:    movt    r1, #:upper16:global1   @ .word e3401000
-; IASM-NEXT:    str     r0, [r1]
+; IASM-NEXT:    movw    r1, #:lower16:global1
+; IASM-NEXT:    movt    r1, #:upper16:global1
+; IASM-NEXT:    .byte 0x0
+; IASM-NEXT:    .byte 0x0
+; IASM-NEXT:    .byte 0x81
+; IASM-NEXT:    .byte 0xe5
 ; IASM-NEXT:    .byte 0x1e
 ; IASM-NEXT:    .byte 0xff
 ; IASM-NEXT:    .byte 0x2f