Test control flow instruction with optimizing compiler.

Add support for basic instructions to implement these tests.

Change-Id: I3870bf9301599043b3511522bb49dc6364c9b4c0
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc
index f89583d..beccf01 100644
--- a/compiler/optimizing/builder.cc
+++ b/compiler/optimizing/builder.cc
@@ -44,15 +44,14 @@
   graph_->SetNumberOfInVRegs(number_of_parameters);
   const char* shorty = dex_compilation_unit_->GetShorty();
   int locals_index = locals_.Size() - number_of_parameters;
-  HBasicBlock* first_block = entry_block_->GetSuccessors()->Get(0);
   int parameter_index = 0;
 
   if (!dex_compilation_unit_->IsStatic()) {
     // Add the implicit 'this' argument, not expressed in the signature.
     HParameterValue* parameter = new (arena_) HParameterValue(parameter_index++);
-    first_block->AddInstruction(parameter);
+    entry_block_->AddInstruction(parameter);
     HLocal* local = GetLocalAt(locals_index++);
-    first_block->AddInstruction(new (arena_) HStoreLocal(local, parameter));
+    entry_block_->AddInstruction(new (arena_) HStoreLocal(local, parameter));
     number_of_parameters--;
   }
 
@@ -68,11 +67,11 @@
       default: {
         // integer and reference parameters.
         HParameterValue* parameter = new (arena_) HParameterValue(parameter_index++);
-        first_block->AddInstruction(parameter);
+        entry_block_->AddInstruction(parameter);
         HLocal* local = GetLocalAt(locals_index++);
         // Store the parameter value in the local that the dex code will use
         // to reference that parameter.
-        first_block->AddInstruction(new (arena_) HStoreLocal(local, parameter));
+        entry_block_->AddInstruction(new (arena_) HStoreLocal(local, parameter));
         break;
       }
     }
@@ -87,6 +86,24 @@
   return true;
 }
 
+template<typename T>
+void HGraphBuilder::If_22t(const Instruction& instruction, int32_t dex_offset, bool is_not) {
+  HInstruction* first = LoadLocal(instruction.VRegA());
+  HInstruction* second = LoadLocal(instruction.VRegB());
+  current_block_->AddInstruction(new (arena_) T(first, second));
+  if (is_not) {
+    current_block_->AddInstruction(new (arena_) HNot(current_block_->GetLastInstruction()));
+  }
+  current_block_->AddInstruction(new (arena_) HIf(current_block_->GetLastInstruction()));
+  HBasicBlock* target = FindBlockStartingAt(instruction.GetTargetOffset() + dex_offset);
+  DCHECK(target != nullptr);
+  current_block_->AddSuccessor(target);
+  target = FindBlockStartingAt(dex_offset + instruction.SizeInCodeUnits());
+  DCHECK(target != nullptr);
+  current_block_->AddSuccessor(target);
+  current_block_ = nullptr;
+}
+
 HGraph* HGraphBuilder::BuildGraph(const DexFile::CodeItem& code_item) {
   if (!CanHandleCodeItem(code_item)) {
     return nullptr;
@@ -238,6 +255,19 @@
       break;
     }
 
+    case Instruction::CONST_16: {
+      int32_t register_index = instruction.VRegA();
+      HIntConstant* constant = GetConstant(instruction.VRegB_21s());
+      UpdateLocal(register_index, constant);
+      break;
+    }
+
+    case Instruction::MOVE: {
+      HInstruction* value = LoadLocal(instruction.VRegB());
+      UpdateLocal(instruction.VRegA(), value);
+      break;
+    }
+
     case Instruction::RETURN_VOID: {
       current_block_->AddInstruction(new (arena_) HReturnVoid());
       current_block_->AddSuccessor(exit_block_);
@@ -246,17 +276,12 @@
     }
 
     case Instruction::IF_EQ: {
-      HInstruction* first = LoadLocal(instruction.VRegA());
-      HInstruction* second = LoadLocal(instruction.VRegB());
-      current_block_->AddInstruction(new (arena_) HEqual(first, second));
-      current_block_->AddInstruction(new (arena_) HIf(current_block_->GetLastInstruction()));
-      HBasicBlock* target = FindBlockStartingAt(instruction.GetTargetOffset() + dex_offset);
-      DCHECK(target != nullptr);
-      current_block_->AddSuccessor(target);
-      target = FindBlockStartingAt(dex_offset + instruction.SizeInCodeUnits());
-      DCHECK(target != nullptr);
-      current_block_->AddSuccessor(target);
-      current_block_ = nullptr;
+      If_22t<HEqual>(instruction, dex_offset, false);
+      break;
+    }
+
+    case Instruction::IF_NE: {
+      If_22t<HEqual>(instruction, dex_offset, true);
       break;
     }
 
diff --git a/compiler/optimizing/builder.h b/compiler/optimizing/builder.h
index df64d71..60d9982 100644
--- a/compiler/optimizing/builder.h
+++ b/compiler/optimizing/builder.h
@@ -79,6 +79,7 @@
   template<typename T> void Binop_12x(const Instruction& instruction);
   template<typename T> void Binop_22b(const Instruction& instruction, bool reverse);
   template<typename T> void Binop_22s(const Instruction& instruction, bool reverse);
+  template<typename T> void If_22t(const Instruction& instruction, int32_t dex_offset, bool is_not);
 
   ArenaAllocator* const arena_;
 
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc
index 40a7b6f..7e63c69 100644
--- a/compiler/optimizing/code_generator.cc
+++ b/compiler/optimizing/code_generator.cc
@@ -33,8 +33,8 @@
   const GrowableArray<HBasicBlock*>* blocks = GetGraph()->GetBlocks();
   DCHECK(blocks->Get(0) == GetGraph()->GetEntryBlock());
   DCHECK(GoesToNextBlock(GetGraph()->GetEntryBlock(), blocks->Get(1)));
-  CompileEntryBlock();
-  for (size_t i = 1; i < blocks->Size(); i++) {
+  GenerateFrameEntry();
+  for (size_t i = 0; i < blocks->Size(); i++) {
     CompileBlock(blocks->Get(i));
   }
   size_t code_size = GetAssembler()->CodeSize();
@@ -43,30 +43,11 @@
   GetAssembler()->FinalizeInstructions(code);
 }
 
-void CodeGenerator::CompileEntryBlock() {
-  HGraphVisitor* location_builder = GetLocationBuilder();
-  HGraphVisitor* instruction_visitor = GetInstructionVisitor();
-  if (kIsDebugBuild) {
-    for (HInstructionIterator it(GetGraph()->GetEntryBlock()); !it.Done(); it.Advance()) {
-      HInstruction* current = it.Current();
-      // Instructions in the entry block should not generate code.
-      current->Accept(location_builder);
-      DCHECK(current->GetLocations() == nullptr);
-      current->Accept(instruction_visitor);
-    }
-  }
-  GenerateFrameEntry();
-}
-
 void CodeGenerator::CompileBlock(HBasicBlock* block) {
   Bind(GetLabelOf(block));
   HGraphVisitor* location_builder = GetLocationBuilder();
   HGraphVisitor* instruction_visitor = GetInstructionVisitor();
   for (HInstructionIterator it(block); !it.Done(); it.Advance()) {
-    // For each instruction, we emulate a stack-based machine, where the inputs are popped from
-    // the runtime stack, and the result is pushed on the stack. We currently can do this because
-    // we do not perform any code motion, and the Dex format does not reference individual
-    // instructions but uses registers instead (our equivalent of HLocal).
     HInstruction* current = it.Current();
     current->Accept(location_builder);
     InitLocations(current);
diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h
index e144733..6648598 100644
--- a/compiler/optimizing/code_generator.h
+++ b/compiler/optimizing/code_generator.h
@@ -180,7 +180,6 @@
  private:
   void InitLocations(HInstruction* instruction);
   void CompileBlock(HBasicBlock* block);
-  void CompileEntryBlock();
 
   HGraph* const graph_;
 
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index 2364bc8..4e88765 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -149,7 +149,6 @@
 
 void InstructionCodeGeneratorARM::VisitLocal(HLocal* local) {
   DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
-  codegen_->SetFrameSize(codegen_->GetFrameSize() + kArmWordSize);
 }
 
 void LocationsBuilderARM::VisitLoadLocal(HLoadLocal* load) {
@@ -384,5 +383,17 @@
   }
 }
 
+void LocationsBuilderARM::VisitNot(HNot* instruction) {
+  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
+  locations->SetInAt(0, Location(R0));
+  locations->SetOut(Location(R0));
+  instruction->SetLocations(locations);
+}
+
+void InstructionCodeGeneratorARM::VisitNot(HNot* instruction) {
+  LocationSummary* locations = instruction->GetLocations();
+  __ eor(locations->Out().reg<Register>(), locations->InAt(0).reg<Register>(), ShifterOperand(1));
+}
+
 }  // namespace arm
 }  // namespace art
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 540a72a..88198dc 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -379,5 +379,18 @@
   }
 }
 
+void LocationsBuilderX86::VisitNot(HNot* instruction) {
+  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
+  locations->SetInAt(0, Location(EAX));
+  locations->SetOut(Location(EAX));
+  instruction->SetLocations(locations);
+}
+
+void InstructionCodeGeneratorX86::VisitNot(HNot* instruction) {
+  LocationSummary* locations = instruction->GetLocations();
+  DCHECK_EQ(locations->InAt(0).reg<Register>(), locations->Out().reg<Register>());
+  __ xorl(locations->Out().reg<Register>(), Immediate(1));
+}
+
 }  // namespace x86
 }  // namespace art
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index d1f672f..adea0ba 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -227,6 +227,7 @@
   M(LoadLocal)                                             \
   M(Local)                                                 \
   M(NewInstance)                                           \
+  M(Not)                                                   \
   M(ParameterValue)                                        \
   M(PushArgument)                                          \
   M(Return)                                                \
@@ -740,6 +741,18 @@
   DISALLOW_COPY_AND_ASSIGN(HParameterValue);
 };
 
+class HNot : public HTemplateInstruction<1> {
+ public:
+  explicit HNot(HInstruction* input) {
+    SetRawInputAt(0, input);
+  }
+
+  DECLARE_INSTRUCTION(Not);
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(HNot);
+};
+
 class HGraphVisitor : public ValueObject {
  public:
   explicit HGraphVisitor(HGraph* graph) : graph_(graph) { }
diff --git a/compiler/utils/x86/assembler_x86.cc b/compiler/utils/x86/assembler_x86.cc
index 6043c17..6a3efc5 100644
--- a/compiler/utils/x86/assembler_x86.cc
+++ b/compiler/utils/x86/assembler_x86.cc
@@ -863,6 +863,10 @@
   EmitOperand(dst, Operand(src));
 }
 
+void X86Assembler::xorl(Register dst, const Immediate& imm) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitComplex(6, Operand(dst), imm);
+}
 
 void X86Assembler::addl(Register reg, const Immediate& imm) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
diff --git a/compiler/utils/x86/assembler_x86.h b/compiler/utils/x86/assembler_x86.h
index f8fc4c0..057c80a 100644
--- a/compiler/utils/x86/assembler_x86.h
+++ b/compiler/utils/x86/assembler_x86.h
@@ -354,6 +354,7 @@
   void orl(Register dst, Register src);
 
   void xorl(Register dst, Register src);
+  void xorl(Register dst, const Immediate& imm);
 
   void addl(Register dst, Register src);
   void addl(Register reg, const Immediate& imm);
diff --git a/test/402-optimizing-control-flow/expected.txt b/test/402-optimizing-control-flow/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/402-optimizing-control-flow/expected.txt
diff --git a/test/402-optimizing-control-flow/info.txt b/test/402-optimizing-control-flow/info.txt
new file mode 100644
index 0000000..37d9458
--- /dev/null
+++ b/test/402-optimizing-control-flow/info.txt
@@ -0,0 +1 @@
+A set of tests for testing control flow instructions on the optimizing compiler.
diff --git a/test/402-optimizing-control-flow/src/Main.java b/test/402-optimizing-control-flow/src/Main.java
new file mode 100644
index 0000000..3339ef4
--- /dev/null
+++ b/test/402-optimizing-control-flow/src/Main.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Note that $opt$ is a marker for the optimizing compiler to ensure
+// it does compile the method.
+
+public class Main {
+
+  public static void expectEquals(int expected, int value) {
+    if (expected != value) {
+      throw new Error("Expected: " + expected + ", found: " + value);
+    }
+  }
+
+  public static void main(String[] args) {
+    int result = $opt$testIfEq1(42);
+    expectEquals(42, result);
+
+    result = $opt$testIfEq2(42);
+    expectEquals(7, result);
+
+    result = $opt$testWhileLoop(42);
+    expectEquals(45, result);
+
+    result = $opt$testDoWhileLoop(42);
+    expectEquals(45, result);
+
+    result = $opt$testForLoop(42);
+    expectEquals(44, result);
+  }
+
+  static int $opt$testIfEq1(int a) {
+    if (a + 1 == 43) {
+      return 42;
+    } else {
+      return 7;
+    }
+  }
+
+  static int $opt$testIfEq2(int a) {
+    if (a + 1 == 41) {
+      return 42;
+    } else {
+      return 7;
+    }
+  }
+
+  static int $opt$testWhileLoop(int a) {
+    while (a++ != 44) {}
+    return a;
+  }
+
+  static int $opt$testDoWhileLoop(int a) {
+    do {
+    } while (a++ != 44);
+    return a;
+  }
+
+  static int $opt$testForLoop(int a) {
+    for (; a != 44; a++) {}
+    return a;
+  }
+}