Subzero ARM: lowerLoad and lowerStore.

Thought leaving "mov" simple and not handle memory operands,
but then we'd have to duplicate some of the lowerAssign code
for lowerLoad =/

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

Review URL: https://codereview.chromium.org/1152703006
diff --git a/src/IceTargetLoweringARM32.cpp b/src/IceTargetLoweringARM32.cpp
index e160a3c..37f5e19 100644
--- a/src/IceTargetLoweringARM32.cpp
+++ b/src/IceTargetLoweringARM32.cpp
@@ -1628,9 +1628,18 @@
   return;
 }
 
-void TargetARM32::lowerLoad(const InstLoad *Inst) {
-  (void)Inst;
-  UnimplementedError(Func->getContext()->getFlags());
+void TargetARM32::lowerLoad(const InstLoad *Load) {
+  // A Load instruction can be treated the same as an Assign
+  // instruction, after the source operand is transformed into an
+  // OperandARM32Mem operand.
+  Type Ty = Load->getDest()->getType();
+  Operand *Src0 = formMemoryOperand(Load->getSourceAddress(), Ty);
+  Variable *DestLoad = Load->getDest();
+
+  // TODO(jvoung): handled folding opportunities. Sign and zero extension
+  // can be folded into a load.
+  InstAssign *Assign = InstAssign::create(Func, DestLoad, Src0);
+  lowerAssign(Assign);
 }
 
 void TargetARM32::doAddressOptLoad() {
@@ -1687,8 +1696,22 @@
 }
 
 void TargetARM32::lowerStore(const InstStore *Inst) {
-  (void)Inst;
-  UnimplementedError(Func->getContext()->getFlags());
+  Operand *Value = Inst->getData();
+  Operand *Addr = Inst->getAddr();
+  OperandARM32Mem *NewAddr = formMemoryOperand(Addr, Value->getType());
+  Type Ty = NewAddr->getType();
+
+  if (Ty == IceType_i64) {
+    Variable *ValueHi = legalizeToVar(hiOperand(Value));
+    Variable *ValueLo = legalizeToVar(loOperand(Value));
+    _str(ValueHi, llvm::cast<OperandARM32Mem>(hiOperand(NewAddr)));
+    _str(ValueLo, llvm::cast<OperandARM32Mem>(loOperand(NewAddr)));
+  } else if (isVectorType(Ty)) {
+    UnimplementedError(Func->getContext()->getFlags());
+  } else {
+    Variable *ValueR = legalizeToVar(Value);
+    _str(ValueR, NewAddr);
+  }
 }
 
 void TargetARM32::doAddressOptStore() {
@@ -1891,6 +1914,23 @@
   return llvm::cast<Variable>(legalize(From, Legal_Reg, RegNum));
 }
 
+OperandARM32Mem *TargetARM32::formMemoryOperand(Operand *Operand, Type Ty) {
+  OperandARM32Mem *Mem = llvm::dyn_cast<OperandARM32Mem>(Operand);
+  // It may be the case that address mode optimization already creates
+  // an OperandARM32Mem, so in that case it wouldn't need another level
+  // of transformation.
+  if (Mem) {
+    return llvm::cast<OperandARM32Mem>(legalize(Mem));
+  }
+  // If we didn't do address mode optimization, then we only
+  // have a base/offset to work with. ARM always requires a base
+  // register, so just use that to hold the operand.
+  Variable *Base = legalizeToVar(Operand);
+  return OperandARM32Mem::create(
+      Func, Ty, Base,
+      llvm::cast<ConstantInteger32>(Ctx->getConstantZero(IceType_i32)));
+}
+
 Variable *TargetARM32::makeReg(Type Type, int32_t RegNum) {
   // There aren't any 64-bit integer registers for ARM32.
   assert(Type != IceType_i64);