More code generation for the optimizing compiler.

- Add HReturn instruction
- Generate code for locals/if/return
- Setup infrastructure for register allocation. Currently
  emulate a stack.

Change-Id: Ib28c2dba80f6c526177ed9a7b09c0689ac8122fb
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index 356e909..62bf7ba 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -24,28 +24,52 @@
 namespace arm {
 
 void CodeGeneratorARM::GenerateFrameEntry() {
-  RegList registers = (1 << LR) | (1 << FP);
-  __ PushList(registers);
+  __ PushList((1 << FP) | (1 << LR));
+  __ mov(FP, ShifterOperand(SP));
+  if (frame_size_ != 0) {
+    __ AddConstant(SP, -frame_size_);
+  }
 }
 
 void CodeGeneratorARM::GenerateFrameExit() {
-  RegList registers = (1 << PC) | (1 << FP);
-  __ PopList(registers);
+  __ mov(SP, ShifterOperand(FP));
+  __ PopList((1 << FP) | (1 << PC));
 }
 
 void CodeGeneratorARM::Bind(Label* label) {
   __ Bind(label);
 }
 
+void CodeGeneratorARM::Push(HInstruction* instruction, Location location) {
+  __ Push(location.reg<Register>());
+}
+
+void CodeGeneratorARM::Move(HInstruction* instruction, Location location) {
+  HIntConstant* constant = instruction->AsIntConstant();
+  if (constant != nullptr) {
+    __ LoadImmediate(location.reg<Register>(), constant->value());
+  } else {
+    __ Pop(location.reg<Register>());
+  }
+}
+
+void LocationsBuilderARM::VisitGoto(HGoto* got) {
+  got->set_locations(nullptr);
+}
+
 void CodeGeneratorARM::VisitGoto(HGoto* got) {
   HBasicBlock* successor = got->GetSuccessor();
   if (graph()->exit_block() == successor) {
     GenerateFrameExit();
-  } else if (!GoesToNextBlock(got)) {
+  } else if (!GoesToNextBlock(got->block(), successor)) {
     __ b(GetLabelOf(successor));
   }
 }
 
+void LocationsBuilderARM::VisitExit(HExit* exit) {
+  exit->set_locations(nullptr);
+}
+
 void CodeGeneratorARM::VisitExit(HExit* exit) {
   if (kIsDebugBuild) {
     __ Comment("Unreachable");
@@ -53,33 +77,101 @@
   }
 }
 
+void LocationsBuilderARM::VisitIf(HIf* if_instr) {
+  LocationSummary* locations = new (graph()->arena()) LocationSummary(if_instr);
+  locations->SetInAt(0, Location(R0));
+  if_instr->set_locations(locations);
+}
+
 void CodeGeneratorARM::VisitIf(HIf* if_instr) {
-  LOG(FATAL) << "UNIMPLEMENTED";
+  // TODO: Generate the input as a condition, instead of materializing in a register.
+  __ cmp(if_instr->locations()->InAt(0).reg<Register>(), ShifterOperand(0));
+  __ b(GetLabelOf(if_instr->IfFalseSuccessor()), EQ);
+  if (!GoesToNextBlock(if_instr->block(), if_instr->IfTrueSuccessor())) {
+    __ b(GetLabelOf(if_instr->IfTrueSuccessor()));
+  }
+}
+
+void LocationsBuilderARM::VisitEqual(HEqual* equal) {
+  LocationSummary* locations = new (graph()->arena()) LocationSummary(equal);
+  locations->SetInAt(0, Location(R0));
+  locations->SetInAt(1, Location(R1));
+  locations->SetOut(Location(R0));
+  equal->set_locations(locations);
 }
 
 void CodeGeneratorARM::VisitEqual(HEqual* equal) {
-  LOG(FATAL) << "UNIMPLEMENTED";
+  LocationSummary* locations = equal->locations();
+  __ teq(locations->InAt(0).reg<Register>(),
+         ShifterOperand(locations->InAt(1).reg<Register>()));
+  __ mov(locations->Out().reg<Register>(), ShifterOperand(1), EQ);
+  __ mov(locations->Out().reg<Register>(), ShifterOperand(0), NE);
+}
+
+void LocationsBuilderARM::VisitLocal(HLocal* local) {
+  local->set_locations(nullptr);
 }
 
 void CodeGeneratorARM::VisitLocal(HLocal* local) {
-  LOG(FATAL) << "UNIMPLEMENTED";
+  DCHECK_EQ(local->block(), graph()->entry_block());
+  frame_size_ += kWordSize;
 }
 
-void CodeGeneratorARM::VisitLoadLocal(HLoadLocal* local) {
-  LOG(FATAL) << "UNIMPLEMENTED";
+void LocationsBuilderARM::VisitLoadLocal(HLoadLocal* load) {
+  LocationSummary* locations = new (graph()->arena()) LocationSummary(load);
+  locations->SetOut(Location(R0));
+  load->set_locations(locations);
 }
 
-void CodeGeneratorARM::VisitStoreLocal(HStoreLocal* local) {
-  LOG(FATAL) << "UNIMPLEMENTED";
+static int32_t GetStackSlot(HLocal* local) {
+  // We are currently using FP to access locals, so the offset must be negative.
+  return (local->reg_number() + 1) * -kWordSize;
+}
+
+void CodeGeneratorARM::VisitLoadLocal(HLoadLocal* load) {
+  LocationSummary* locations = load->locations();
+  __ LoadFromOffset(kLoadWord, locations->Out().reg<Register>(),
+                    FP, GetStackSlot(load->GetLocal()));
+}
+
+void LocationsBuilderARM::VisitStoreLocal(HStoreLocal* store) {
+  LocationSummary* locations = new (graph()->arena()) LocationSummary(store);
+  locations->SetInAt(1, Location(R0));
+  store->set_locations(locations);
+}
+
+void CodeGeneratorARM::VisitStoreLocal(HStoreLocal* store) {
+  LocationSummary* locations = store->locations();
+  __ StoreToOffset(kStoreWord, locations->InAt(1).reg<Register>(),
+                   FP, GetStackSlot(store->GetLocal()));
+}
+
+void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) {
+  constant->set_locations(nullptr);
 }
 
 void CodeGeneratorARM::VisitIntConstant(HIntConstant* constant) {
-  LOG(FATAL) << "UNIMPLEMENTED";
+  // Will be generated at use site.
+}
+
+void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) {
+  ret->set_locations(nullptr);
 }
 
 void CodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret) {
   GenerateFrameExit();
 }
 
+void LocationsBuilderARM::VisitReturn(HReturn* ret) {
+  LocationSummary* locations = new (graph()->arena()) LocationSummary(ret);
+  locations->SetInAt(0, Location(R0));
+  ret->set_locations(locations);
+}
+
+void CodeGeneratorARM::VisitReturn(HReturn* ret) {
+  DCHECK_EQ(ret->locations()->InAt(0).reg<Register>(), R0);
+  GenerateFrameExit();
+}
+
 }  // namespace arm
 }  // namespace art