Implement int bit-wise not operation in the optimizing compiler.

- Add support for the not-int (integer one's complement
  negate) instruction in the optimizing compiler.
- Extend the HNot control-flow graph node type and make it
  inherit from HUnaryOperation.
- Generate ARM, x86 and x86-64 code for integer HNeg nodes.
- Exercise these additions in the codegen_test gtest, as there
  is not direct way to assess the support of not-int from a
  Java source.  Indeed, compiling a Java expression such as
  `~a' using javac and then dx generates an xor-int/lit8 Dex
  instruction instead of the expected not-int Dex instruction.
  This is probably because the Java bytecode has an `ixor'
  instruction, but there's not instruction directly
  corresponding to a bit-wise not operation.

Change-Id: I223aed75c4dac5785e04d99da0d22e8d699aee2b
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc
index 4d575cb..f48f4c3 100644
--- a/compiler/optimizing/builder.cc
+++ b/compiler/optimizing/builder.cc
@@ -748,6 +748,11 @@
       break;
     }
 
+    case Instruction::NOT_INT: {
+      Unop_12x<HNot>(instruction, Primitive::kPrimInt);
+      break;
+    }
+
     case Instruction::ADD_INT: {
       Binop_23x<HAdd>(instruction, Primitive::kPrimInt);
       break;
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index 7ed802e..b042beb 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -1351,17 +1351,33 @@
   // Nothing to do, the parameter is already at its location.
 }
 
-void LocationsBuilderARM::VisitNot(HNot* instruction) {
+void LocationsBuilderARM::VisitNot(HNot* not_) {
   LocationSummary* locations =
-      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
+      new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
   locations->SetInAt(0, Location::RequiresRegister());
   locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
 }
 
-void InstructionCodeGeneratorARM::VisitNot(HNot* instruction) {
-  LocationSummary* locations = instruction->GetLocations();
-  __ eor(locations->Out().As<Register>(),
-         locations->InAt(0).As<Register>(), ShifterOperand(1));
+void InstructionCodeGeneratorARM::VisitNot(HNot* not_) {
+  LocationSummary* locations = not_->GetLocations();
+  Location out = locations->Out();
+  Location in = locations->InAt(0);
+  switch (not_->InputAt(0)->GetType()) {
+    case Primitive::kPrimBoolean:
+      __ eor(out.As<Register>(), in.As<Register>(), ShifterOperand(1));
+      break;
+
+    case Primitive::kPrimInt:
+      __ mvn(out.As<Register>(), ShifterOperand(in.As<Register>()));
+      break;
+
+    case Primitive::kPrimLong:
+      LOG(FATAL) << "Not yet implemented type for not operation " << not_->GetResultType();
+      break;
+
+    default:
+      LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
+  }
 }
 
 void LocationsBuilderARM::VisitCompare(HCompare* compare) {
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 5f01265..3b4b835 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -1356,18 +1356,34 @@
 void InstructionCodeGeneratorX86::VisitParameterValue(HParameterValue* instruction) {
 }
 
-void LocationsBuilderX86::VisitNot(HNot* instruction) {
+void LocationsBuilderX86::VisitNot(HNot* not_) {
   LocationSummary* locations =
-      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
+      new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
   locations->SetInAt(0, Location::RequiresRegister());
   locations->SetOut(Location::SameAsFirstInput());
 }
 
-void InstructionCodeGeneratorX86::VisitNot(HNot* instruction) {
-  LocationSummary* locations = instruction->GetLocations();
+void InstructionCodeGeneratorX86::VisitNot(HNot* not_) {
+  LocationSummary* locations = not_->GetLocations();
+  DCHECK_EQ(locations->InAt(0).As<Register>(), locations->Out().As<Register>());
   Location out = locations->Out();
   DCHECK_EQ(locations->InAt(0).As<Register>(), out.As<Register>());
-  __ xorl(out.As<Register>(), Immediate(1));
+  switch (not_->InputAt(0)->GetType()) {
+    case Primitive::kPrimBoolean:
+      __ xorl(out.As<Register>(), Immediate(1));
+      break;
+
+    case Primitive::kPrimInt:
+      __ notl(out.As<Register>());
+      break;
+
+    case Primitive::kPrimLong:
+      LOG(FATAL) << "Not yet implemented type for not operation " << not_->GetResultType();
+      break;
+
+    default:
+      LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
+  }
 }
 
 void LocationsBuilderX86::VisitCompare(HCompare* compare) {
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index 38a40dc..ac623f6 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -1276,18 +1276,34 @@
   // Nothing to do, the parameter is already at its location.
 }
 
-void LocationsBuilderX86_64::VisitNot(HNot* instruction) {
+void LocationsBuilderX86_64::VisitNot(HNot* not_) {
   LocationSummary* locations =
-      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
+      new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
   locations->SetInAt(0, Location::RequiresRegister());
   locations->SetOut(Location::SameAsFirstInput());
 }
 
-void InstructionCodeGeneratorX86_64::VisitNot(HNot* instruction) {
-  LocationSummary* locations = instruction->GetLocations();
+void InstructionCodeGeneratorX86_64::VisitNot(HNot* not_) {
+  LocationSummary* locations = not_->GetLocations();
   DCHECK_EQ(locations->InAt(0).As<CpuRegister>().AsRegister(),
             locations->Out().As<CpuRegister>().AsRegister());
-  __ xorq(locations->Out().As<CpuRegister>(), Immediate(1));
+  Location out = locations->Out();
+  switch (not_->InputAt(0)->GetType()) {
+    case Primitive::kPrimBoolean:
+      __ xorq(out.As<CpuRegister>(), Immediate(1));
+      break;
+
+    case Primitive::kPrimInt:
+      __ notl(out.As<CpuRegister>());
+      break;
+
+    case Primitive::kPrimLong:
+      LOG(FATAL) << "Not yet implemented type for not operation " << not_->GetResultType();
+      break;
+
+    default:
+      LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
+  }
 }
 
 void LocationsBuilderX86_64::VisitPhi(HPhi* instruction) {
diff --git a/compiler/optimizing/codegen_test.cc b/compiler/optimizing/codegen_test.cc
index af4cf73..a84931a 100644
--- a/compiler/optimizing/codegen_test.cc
+++ b/compiler/optimizing/codegen_test.cc
@@ -260,6 +260,31 @@
   TestCode(data, true, 0);
 }
 
+// Exercise bit-wise (one's complement) not-int instruction.
+#define NOT_INT_TEST(TEST_NAME, INPUT, EXPECTED_OUTPUT) \
+TEST(CodegenTest, TEST_NAME) {                          \
+  const int32_t input = INPUT;                          \
+  const uint16_t input_lo = input & 0x0000FFFF;         \
+  const uint16_t input_hi = input >> 16;                \
+  const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(      \
+      Instruction::CONST | 0 << 8, input_lo, input_hi,  \
+      Instruction::NOT_INT | 1 << 8 | 0 << 12 ,         \
+      Instruction::RETURN | 1 << 8);                    \
+                                                        \
+  TestCode(data, true, EXPECTED_OUTPUT);                \
+}
+
+NOT_INT_TEST(ReturnNotIntMinus2, -2, 1)
+NOT_INT_TEST(ReturnNotIntMinus1, -1, 0)
+NOT_INT_TEST(ReturnNotInt0, 0, -1)
+NOT_INT_TEST(ReturnNotInt1, 1, -2)
+NOT_INT_TEST(ReturnNotIntINT_MIN, -2147483648, 2147483647)  // (2^31) - 1
+NOT_INT_TEST(ReturnNotIntINT_MINPlus1, -2147483647, 2147483646)  // (2^31) - 2
+NOT_INT_TEST(ReturnNotIntINT_MAXMinus1, 2147483646, -2147483647)  // -(2^31) - 1
+NOT_INT_TEST(ReturnNotIntINT_MAX, 2147483647, -2147483648)  // -(2^31)
+
+#undef NOT_INT_TEST
+
 TEST(CodegenTest, ReturnAdd1) {
   const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
     Instruction::CONST_4 | 3 << 12 | 0,
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc
index 2d9e35c..29eabe7 100644
--- a/compiler/optimizing/instruction_simplifier.cc
+++ b/compiler/optimizing/instruction_simplifier.cc
@@ -50,7 +50,7 @@
       // Replace (bool_value == 0) with !bool_value
       DCHECK_EQ(input2->AsIntConstant()->GetValue(), 0);
       equal->GetBlock()->ReplaceAndRemoveInstructionWith(
-          equal, new (GetGraph()->GetArena()) HNot(input1));
+          equal, new (GetGraph()->GetArena()) HNot(Primitive::kPrimBoolean, input1));
     }
   }
 }
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 9b7ff88..9c923d6 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -485,7 +485,7 @@
   M(Local, Instruction)                                                 \
   M(LongConstant, Constant)                                             \
   M(NewInstance, Instruction)                                           \
-  M(Not, Instruction)                                                   \
+  M(Not, UnaryOperation)                                                \
   M(ParameterValue, Instruction)                                        \
   M(ParallelMove, Instruction)                                          \
   M(Phi, Instruction)                                                   \
@@ -1708,15 +1708,17 @@
   DISALLOW_COPY_AND_ASSIGN(HParameterValue);
 };
 
-class HNot : public HExpression<1> {
+class HNot : public HUnaryOperation {
  public:
-  explicit HNot(HInstruction* input) : HExpression(Primitive::kPrimBoolean, SideEffects::None()) {
-    SetRawInputAt(0, input);
-  }
+  explicit HNot(Primitive::Type result_type, HInstruction* input)
+      : HUnaryOperation(result_type, input) {}
 
   virtual bool CanBeMoved() const { return true; }
   virtual bool InstructionDataEquals(HInstruction* other) const { return true; }
 
+  virtual int32_t Evaluate(int32_t x) const OVERRIDE { return ~x; }
+  virtual int64_t Evaluate(int64_t x) const OVERRIDE { return ~x; }
+
   DECLARE_INSTRUCTION(Not);
 
  private: