Implement and/or/xor in optimizing.

Change-Id: I7cf6da1fd334a7177a5580931b8f174dd40b7cec
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc
index e338178..d3ac4e0 100644
--- a/compiler/optimizing/builder.cc
+++ b/compiler/optimizing/builder.cc
@@ -1047,6 +1047,36 @@
       break;
     }
 
+    case Instruction::AND_INT: {
+      Binop_23x<HAnd>(instruction, Primitive::kPrimInt);
+      break;
+    }
+
+    case Instruction::AND_LONG: {
+      Binop_23x<HAnd>(instruction, Primitive::kPrimLong);
+      break;
+    }
+
+    case Instruction::OR_INT: {
+      Binop_23x<HOr>(instruction, Primitive::kPrimInt);
+      break;
+    }
+
+    case Instruction::OR_LONG: {
+      Binop_23x<HOr>(instruction, Primitive::kPrimLong);
+      break;
+    }
+
+    case Instruction::XOR_INT: {
+      Binop_23x<HXor>(instruction, Primitive::kPrimInt);
+      break;
+    }
+
+    case Instruction::XOR_LONG: {
+      Binop_23x<HXor>(instruction, Primitive::kPrimLong);
+      break;
+    }
+
     case Instruction::ADD_LONG_2ADDR: {
       Binop_12x<HAdd>(instruction, Primitive::kPrimLong);
       break;
@@ -1118,11 +1148,56 @@
       break;
     }
 
+    case Instruction::AND_INT_2ADDR: {
+      Binop_12x<HAnd>(instruction, Primitive::kPrimInt);
+      break;
+    }
+
+    case Instruction::AND_LONG_2ADDR: {
+      Binop_12x<HAnd>(instruction, Primitive::kPrimLong);
+      break;
+    }
+
+    case Instruction::OR_INT_2ADDR: {
+      Binop_12x<HOr>(instruction, Primitive::kPrimInt);
+      break;
+    }
+
+    case Instruction::OR_LONG_2ADDR: {
+      Binop_12x<HOr>(instruction, Primitive::kPrimLong);
+      break;
+    }
+
+    case Instruction::XOR_INT_2ADDR: {
+      Binop_12x<HXor>(instruction, Primitive::kPrimInt);
+      break;
+    }
+
+    case Instruction::XOR_LONG_2ADDR: {
+      Binop_12x<HXor>(instruction, Primitive::kPrimLong);
+      break;
+    }
+
     case Instruction::ADD_INT_LIT16: {
       Binop_22s<HAdd>(instruction, false);
       break;
     }
 
+    case Instruction::AND_INT_LIT16: {
+      Binop_22s<HAnd>(instruction, false);
+      break;
+    }
+
+    case Instruction::OR_INT_LIT16: {
+      Binop_22s<HOr>(instruction, false);
+      break;
+    }
+
+    case Instruction::XOR_INT_LIT16: {
+      Binop_22s<HXor>(instruction, false);
+      break;
+    }
+
     case Instruction::RSUB_INT: {
       Binop_22s<HSub>(instruction, true);
       break;
@@ -1138,6 +1213,21 @@
       break;
     }
 
+    case Instruction::AND_INT_LIT8: {
+      Binop_22b<HAnd>(instruction, false);
+      break;
+    }
+
+    case Instruction::OR_INT_LIT8: {
+      Binop_22b<HOr>(instruction, false);
+      break;
+    }
+
+    case Instruction::XOR_INT_LIT8: {
+      Binop_22b<HXor>(instruction, false);
+      break;
+    }
+
     case Instruction::RSUB_INT_LIT8: {
       Binop_22b<HSub>(instruction, true);
       break;
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index c2e9a2e..56546c2 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -2809,5 +2809,78 @@
       instruction->GetDexPc());
 }
 
+void LocationsBuilderARM::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); }
+void LocationsBuilderARM::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); }
+void LocationsBuilderARM::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); }
+
+void LocationsBuilderARM::HandleBitwiseOperation(HBinaryOperation* instruction) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
+  DCHECK(instruction->GetResultType() == Primitive::kPrimInt
+         || instruction->GetResultType() == Primitive::kPrimLong);
+  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetInAt(1, Location::RequiresRegister());
+  bool output_overlaps = (instruction->GetResultType() == Primitive::kPrimLong);
+  locations->SetOut(Location::RequiresRegister(), output_overlaps);
+}
+
+void InstructionCodeGeneratorARM::VisitAnd(HAnd* instruction) {
+  HandleBitwiseOperation(instruction);
+}
+
+void InstructionCodeGeneratorARM::VisitOr(HOr* instruction) {
+  HandleBitwiseOperation(instruction);
+}
+
+void InstructionCodeGeneratorARM::VisitXor(HXor* instruction) {
+  HandleBitwiseOperation(instruction);
+}
+
+void InstructionCodeGeneratorARM::HandleBitwiseOperation(HBinaryOperation* instruction) {
+  LocationSummary* locations = instruction->GetLocations();
+
+  if (instruction->GetResultType() == Primitive::kPrimInt) {
+    Register first = locations->InAt(0).As<Register>();
+    Register second = locations->InAt(1).As<Register>();
+    Register out = locations->Out().As<Register>();
+    if (instruction->IsAnd()) {
+      __ and_(out, first, ShifterOperand(second));
+    } else if (instruction->IsOr()) {
+      __ orr(out, first, ShifterOperand(second));
+    } else {
+      DCHECK(instruction->IsXor());
+      __ eor(out, first, ShifterOperand(second));
+    }
+  } else {
+    DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
+    Location first = locations->InAt(0);
+    Location second = locations->InAt(1);
+    Location out = locations->Out();
+    if (instruction->IsAnd()) {
+      __ and_(out.AsRegisterPairLow<Register>(),
+              first.AsRegisterPairLow<Register>(),
+              ShifterOperand(second.AsRegisterPairLow<Register>()));
+      __ and_(out.AsRegisterPairHigh<Register>(),
+              first.AsRegisterPairHigh<Register>(),
+              ShifterOperand(second.AsRegisterPairHigh<Register>()));
+    } else if (instruction->IsOr()) {
+      __ orr(out.AsRegisterPairLow<Register>(),
+             first.AsRegisterPairLow<Register>(),
+             ShifterOperand(second.AsRegisterPairLow<Register>()));
+      __ orr(out.AsRegisterPairHigh<Register>(),
+             first.AsRegisterPairHigh<Register>(),
+             ShifterOperand(second.AsRegisterPairHigh<Register>()));
+    } else {
+      DCHECK(instruction->IsXor());
+      __ eor(out.AsRegisterPairLow<Register>(),
+             first.AsRegisterPairLow<Register>(),
+             ShifterOperand(second.AsRegisterPairLow<Register>()));
+      __ eor(out.AsRegisterPairHigh<Register>(),
+             first.AsRegisterPairHigh<Register>(),
+             ShifterOperand(second.AsRegisterPairHigh<Register>()));
+    }
+  }
+}
+
 }  // namespace arm
 }  // namespace art
diff --git a/compiler/optimizing/code_generator_arm.h b/compiler/optimizing/code_generator_arm.h
index 5d51993..d695310 100644
--- a/compiler/optimizing/code_generator_arm.h
+++ b/compiler/optimizing/code_generator_arm.h
@@ -105,9 +105,10 @@
 
 #undef DECLARE_VISIT_INSTRUCTION
 
-  void HandleInvoke(HInvoke* invoke);
-
  private:
+  void HandleInvoke(HInvoke* invoke);
+  void HandleBitwiseOperation(HBinaryOperation* operation);
+
   CodeGeneratorARM* const codegen_;
   InvokeDexCallingConventionVisitor parameter_visitor_;
 
@@ -133,6 +134,7 @@
   // the suspend call.
   void GenerateSuspendCheck(HSuspendCheck* check, HBasicBlock* successor);
   void GenerateClassInitializationCheck(SlowPathCodeARM* slow_path, Register class_reg);
+  void HandleBitwiseOperation(HBinaryOperation* operation);
 
   ArmAssembler* const assembler_;
   CodeGeneratorARM* const codegen_;
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index 95c2fe7..887a4ef 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -631,6 +631,7 @@
         codegen_(codegen) {}
 
 #define FOR_EACH_UNIMPLEMENTED_INSTRUCTION(M)              \
+  M(And)                                                   \
   M(CheckCast)                                             \
   M(ClinitCheck)                                           \
   M(DivZeroCheck)                                          \
@@ -640,11 +641,13 @@
   M(LoadException)                                         \
   M(LoadString)                                            \
   M(MonitorOperation)                                      \
+  M(Or)                                                    \
   M(ParallelMove)                                          \
   M(StaticFieldGet)                                        \
   M(StaticFieldSet)                                        \
   M(Throw)                                                 \
   M(TypeConversion)                                        \
+  M(Xor)                                                    \
 
 #define UNIMPLEMENTED_INSTRUCTION_BREAK_CODE(name) name##UnimplementedInstructionBreakCode
 
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index bed44b2..d470345 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -1448,7 +1448,7 @@
     }
 
     case Primitive::kPrimLong: {
-      if (second.IsRegister()) {
+      if (second.IsRegisterPair()) {
         __ addl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
         __ adcl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
       } else {
@@ -1524,7 +1524,7 @@
     }
 
     case Primitive::kPrimLong: {
-      if (second.IsRegister()) {
+      if (second.IsRegisterPair()) {
         __ subl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
         __ sbbl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
       } else {
@@ -2919,5 +2919,99 @@
   codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
 }
 
+void LocationsBuilderX86::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); }
+void LocationsBuilderX86::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); }
+void LocationsBuilderX86::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); }
+
+void LocationsBuilderX86::HandleBitwiseOperation(HBinaryOperation* instruction) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
+  DCHECK(instruction->GetResultType() == Primitive::kPrimInt
+         || instruction->GetResultType() == Primitive::kPrimLong);
+  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetInAt(1, Location::Any());
+  locations->SetOut(Location::SameAsFirstInput());
+}
+
+void InstructionCodeGeneratorX86::VisitAnd(HAnd* instruction) {
+  HandleBitwiseOperation(instruction);
+}
+
+void InstructionCodeGeneratorX86::VisitOr(HOr* instruction) {
+  HandleBitwiseOperation(instruction);
+}
+
+void InstructionCodeGeneratorX86::VisitXor(HXor* instruction) {
+  HandleBitwiseOperation(instruction);
+}
+
+void InstructionCodeGeneratorX86::HandleBitwiseOperation(HBinaryOperation* instruction) {
+  LocationSummary* locations = instruction->GetLocations();
+  Location first = locations->InAt(0);
+  Location second = locations->InAt(1);
+  DCHECK(first.Equals(locations->Out()));
+
+  if (instruction->GetResultType() == Primitive::kPrimInt) {
+    if (second.IsRegister()) {
+      if (instruction->IsAnd()) {
+        __ andl(first.As<Register>(), second.As<Register>());
+      } else if (instruction->IsOr()) {
+        __ orl(first.As<Register>(), second.As<Register>());
+      } else {
+        DCHECK(instruction->IsXor());
+        __ xorl(first.As<Register>(), second.As<Register>());
+      }
+    } else if (second.IsConstant()) {
+      if (instruction->IsAnd()) {
+        __ andl(first.As<Register>(), Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
+      } else if (instruction->IsOr()) {
+        __ orl(first.As<Register>(), Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
+      } else {
+        DCHECK(instruction->IsXor());
+        __ xorl(first.As<Register>(), Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
+      }
+    } else {
+      if (instruction->IsAnd()) {
+        __ andl(first.As<Register>(), Address(ESP, second.GetStackIndex()));
+      } else if (instruction->IsOr()) {
+        __ orl(first.As<Register>(), Address(ESP, second.GetStackIndex()));
+      } else {
+        DCHECK(instruction->IsXor());
+        __ xorl(first.As<Register>(), Address(ESP, second.GetStackIndex()));
+      }
+    }
+  } else {
+    DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
+    if (second.IsRegisterPair()) {
+      if (instruction->IsAnd()) {
+        __ andl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
+        __ andl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
+      } else if (instruction->IsOr()) {
+        __ orl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
+        __ orl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
+      } else {
+        DCHECK(instruction->IsXor());
+        __ xorl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
+        __ xorl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
+      }
+    } else {
+      if (instruction->IsAnd()) {
+        __ andl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
+        __ andl(first.AsRegisterPairHigh<Register>(),
+                Address(ESP, second.GetHighStackIndex(kX86WordSize)));
+      } else if (instruction->IsOr()) {
+        __ orl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
+        __ orl(first.AsRegisterPairHigh<Register>(),
+                Address(ESP, second.GetHighStackIndex(kX86WordSize)));
+      } else {
+        DCHECK(instruction->IsXor());
+        __ xorl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
+        __ xorl(first.AsRegisterPairHigh<Register>(),
+                Address(ESP, second.GetHighStackIndex(kX86WordSize)));
+      }
+    }
+  }
+}
+
 }  // namespace x86
 }  // namespace art
diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h
index 85fe21c..9e42b0a 100644
--- a/compiler/optimizing/code_generator_x86.h
+++ b/compiler/optimizing/code_generator_x86.h
@@ -100,9 +100,10 @@
 
 #undef DECLARE_VISIT_INSTRUCTION
 
+ private:
+  void HandleBitwiseOperation(HBinaryOperation* instruction);
   void HandleInvoke(HInvoke* invoke);
 
- private:
   CodeGeneratorX86* const codegen_;
   InvokeDexCallingConventionVisitor parameter_visitor_;
 
@@ -128,6 +129,7 @@
   // the suspend call.
   void GenerateSuspendCheck(HSuspendCheck* check, HBasicBlock* successor);
   void GenerateClassInitializationCheck(SlowPathCodeX86* slow_path, Register class_reg);
+  void HandleBitwiseOperation(HBinaryOperation* instruction);
 
   X86Assembler* const assembler_;
   CodeGeneratorX86* const codegen_;
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index 112c179..3c7dd3f 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -2910,5 +2910,86 @@
   codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
 }
 
+void LocationsBuilderX86_64::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); }
+void LocationsBuilderX86_64::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); }
+void LocationsBuilderX86_64::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); }
+
+void LocationsBuilderX86_64::HandleBitwiseOperation(HBinaryOperation* instruction) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
+  DCHECK(instruction->GetResultType() == Primitive::kPrimInt
+         || instruction->GetResultType() == Primitive::kPrimLong);
+  locations->SetInAt(0, Location::RequiresRegister());
+  if (instruction->GetType() == Primitive::kPrimInt) {
+    locations->SetInAt(1, Location::Any());
+  } else {
+    // Request a register to avoid loading a 64bits constant.
+    locations->SetInAt(1, Location::RequiresRegister());
+  }
+  locations->SetOut(Location::SameAsFirstInput());
+}
+
+void InstructionCodeGeneratorX86_64::VisitAnd(HAnd* instruction) {
+  HandleBitwiseOperation(instruction);
+}
+
+void InstructionCodeGeneratorX86_64::VisitOr(HOr* instruction) {
+  HandleBitwiseOperation(instruction);
+}
+
+void InstructionCodeGeneratorX86_64::VisitXor(HXor* instruction) {
+  HandleBitwiseOperation(instruction);
+}
+
+void InstructionCodeGeneratorX86_64::HandleBitwiseOperation(HBinaryOperation* instruction) {
+  LocationSummary* locations = instruction->GetLocations();
+  Location first = locations->InAt(0);
+  Location second = locations->InAt(1);
+  DCHECK(first.Equals(locations->Out()));
+
+  if (instruction->GetResultType() == Primitive::kPrimInt) {
+    if (second.IsRegister()) {
+      if (instruction->IsAnd()) {
+        __ andl(first.As<CpuRegister>(), second.As<CpuRegister>());
+      } else if (instruction->IsOr()) {
+        __ orl(first.As<CpuRegister>(), second.As<CpuRegister>());
+      } else {
+        DCHECK(instruction->IsXor());
+        __ xorl(first.As<CpuRegister>(), second.As<CpuRegister>());
+      }
+    } else if (second.IsConstant()) {
+      Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
+      if (instruction->IsAnd()) {
+        __ andl(first.As<CpuRegister>(), imm);
+      } else if (instruction->IsOr()) {
+        __ orl(first.As<CpuRegister>(), imm);
+      } else {
+        DCHECK(instruction->IsXor());
+        __ xorl(first.As<CpuRegister>(), imm);
+      }
+    } else {
+      Address address(CpuRegister(RSP), second.GetStackIndex());
+      if (instruction->IsAnd()) {
+        __ andl(first.As<CpuRegister>(), address);
+      } else if (instruction->IsOr()) {
+        __ orl(first.As<CpuRegister>(), address);
+      } else {
+        DCHECK(instruction->IsXor());
+        __ xorl(first.As<CpuRegister>(), address);
+      }
+    }
+  } else {
+    DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
+    if (instruction->IsAnd()) {
+      __ andq(first.As<CpuRegister>(), second.As<CpuRegister>());
+    } else if (instruction->IsOr()) {
+      __ orq(first.As<CpuRegister>(), second.As<CpuRegister>());
+    } else {
+      DCHECK(instruction->IsXor());
+      __ xorq(first.As<CpuRegister>(), second.As<CpuRegister>());
+    }
+  }
+}
+
 }  // namespace x86_64
 }  // namespace art
diff --git a/compiler/optimizing/code_generator_x86_64.h b/compiler/optimizing/code_generator_x86_64.h
index 9565b6f..52806f3 100644
--- a/compiler/optimizing/code_generator_x86_64.h
+++ b/compiler/optimizing/code_generator_x86_64.h
@@ -104,9 +104,10 @@
 
 #undef DECLARE_VISIT_INSTRUCTION
 
-  void HandleInvoke(HInvoke* invoke);
-
  private:
+  void HandleInvoke(HInvoke* invoke);
+  void HandleBitwiseOperation(HBinaryOperation* operation);
+
   CodeGeneratorX86_64* const codegen_;
   InvokeDexCallingConventionVisitor parameter_visitor_;
 
@@ -132,6 +133,7 @@
   // the suspend call.
   void GenerateSuspendCheck(HSuspendCheck* instruction, HBasicBlock* successor);
   void GenerateClassInitializationCheck(SlowPathCodeX86_64* slow_path, CpuRegister class_reg);
+  void HandleBitwiseOperation(HBinaryOperation* operation);
 
   X86_64Assembler* const assembler_;
   CodeGeneratorX86_64* const codegen_;
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 1545b0a..6224a11 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -475,6 +475,7 @@
 
 #define FOR_EACH_CONCRETE_INSTRUCTION(M)                                \
   M(Add, BinaryOperation)                                               \
+  M(And, BinaryOperation)                                               \
   M(ArrayGet, Instruction)                                              \
   M(ArrayLength, Instruction)                                           \
   M(ArraySet, Instruction)                                              \
@@ -516,6 +517,7 @@
   M(Not, UnaryOperation)                                                \
   M(NotEqual, Condition)                                                \
   M(NullCheck, Instruction)                                             \
+  M(Or, BinaryOperation)                                                \
   M(ParallelMove, Instruction)                                          \
   M(ParameterValue, Instruction)                                        \
   M(Phi, Instruction)                                                   \
@@ -529,6 +531,7 @@
   M(Temporary, Instruction)                                             \
   M(Throw, Instruction)                                                 \
   M(TypeConversion, Instruction)                                        \
+  M(Xor, BinaryOperation)                                               \
 
 #define FOR_EACH_INSTRUCTION(M)                                         \
   FOR_EACH_CONCRETE_INSTRUCTION(M)                                      \
@@ -1791,6 +1794,54 @@
   DISALLOW_COPY_AND_ASSIGN(HDivZeroCheck);
 };
 
+class HAnd : public HBinaryOperation {
+ public:
+  HAnd(Primitive::Type result_type, HInstruction* left, HInstruction* right)
+      : HBinaryOperation(result_type, left, right) {}
+
+  bool IsCommutative() OVERRIDE { return true; }
+
+  int32_t Evaluate(int32_t x, int32_t y) const OVERRIDE { return x & y; }
+  int64_t Evaluate(int64_t x, int64_t y) const OVERRIDE { return x & y; }
+
+  DECLARE_INSTRUCTION(And);
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(HAnd);
+};
+
+class HOr : public HBinaryOperation {
+ public:
+  HOr(Primitive::Type result_type, HInstruction* left, HInstruction* right)
+      : HBinaryOperation(result_type, left, right) {}
+
+  bool IsCommutative() OVERRIDE { return true; }
+
+  int32_t Evaluate(int32_t x, int32_t y) const OVERRIDE { return x | y; }
+  int64_t Evaluate(int64_t x, int64_t y) const OVERRIDE { return x | y; }
+
+  DECLARE_INSTRUCTION(Or);
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(HOr);
+};
+
+class HXor : public HBinaryOperation {
+ public:
+  HXor(Primitive::Type result_type, HInstruction* left, HInstruction* right)
+      : HBinaryOperation(result_type, left, right) {}
+
+  bool IsCommutative() OVERRIDE { return true; }
+
+  int32_t Evaluate(int32_t x, int32_t y) const OVERRIDE { return x ^ y; }
+  int64_t Evaluate(int64_t x, int64_t y) const OVERRIDE { return x ^ y; }
+
+  DECLARE_INSTRUCTION(Xor);
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(HXor);
+};
+
 // The value of a parameter in this method. Its location depends on
 // the calling convention.
 class HParameterValue : public HExpression<0> {
diff --git a/compiler/utils/x86/assembler_x86.cc b/compiler/utils/x86/assembler_x86.cc
index 4ddf979..8ebb40e 100644
--- a/compiler/utils/x86/assembler_x86.cc
+++ b/compiler/utils/x86/assembler_x86.cc
@@ -873,6 +873,13 @@
 }
 
 
+void X86Assembler::andl(Register reg, const Address& address) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0x23);
+  EmitOperand(reg, address);
+}
+
+
 void X86Assembler::andl(Register dst, const Immediate& imm) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitComplex(4, Operand(dst), imm);
@@ -886,6 +893,13 @@
 }
 
 
+void X86Assembler::orl(Register reg, const Address& address) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0x0B);
+  EmitOperand(reg, address);
+}
+
+
 void X86Assembler::orl(Register dst, const Immediate& imm) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitComplex(1, Operand(dst), imm);
@@ -898,11 +912,20 @@
   EmitOperand(dst, Operand(src));
 }
 
+
+void X86Assembler::xorl(Register reg, const Address& address) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0x33);
+  EmitOperand(reg, address);
+}
+
+
 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_);
   EmitComplex(0, Operand(reg), imm);
diff --git a/compiler/utils/x86/assembler_x86.h b/compiler/utils/x86/assembler_x86.h
index de4e6de..8aed934 100644
--- a/compiler/utils/x86/assembler_x86.h
+++ b/compiler/utils/x86/assembler_x86.h
@@ -350,12 +350,15 @@
 
   void andl(Register dst, const Immediate& imm);
   void andl(Register dst, Register src);
+  void andl(Register dst, const Address& address);
 
   void orl(Register dst, const Immediate& imm);
   void orl(Register dst, Register src);
+  void orl(Register dst, const Address& address);
 
   void xorl(Register dst, Register src);
   void xorl(Register dst, const Immediate& imm);
+  void xorl(Register dst, const Address& address);
 
   void addl(Register dst, Register src);
   void addl(Register reg, const Immediate& imm);
diff --git a/compiler/utils/x86_64/assembler_x86_64.cc b/compiler/utils/x86_64/assembler_x86_64.cc
index c75fa78..5d1c9af 100644
--- a/compiler/utils/x86_64/assembler_x86_64.cc
+++ b/compiler/utils/x86_64/assembler_x86_64.cc
@@ -1014,6 +1014,14 @@
 }
 
 
+void X86_64Assembler::andl(CpuRegister reg, const Address& address) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitOptionalRex32(reg, address);
+  EmitUint8(0x23);
+  EmitOperand(reg.LowBits(), address);
+}
+
+
 void X86_64Assembler::andl(CpuRegister dst, const Immediate& imm) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitOptionalRex32(dst);
@@ -1029,6 +1037,14 @@
 }
 
 
+void X86_64Assembler::andq(CpuRegister dst, CpuRegister src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitRex64(dst, src);
+  EmitUint8(0x23);
+  EmitOperand(dst.LowBits(), Operand(src));
+}
+
+
 void X86_64Assembler::orl(CpuRegister dst, CpuRegister src) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitOptionalRex32(dst, src);
@@ -1037,6 +1053,14 @@
 }
 
 
+void X86_64Assembler::orl(CpuRegister reg, const Address& address) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitOptionalRex32(reg, address);
+  EmitUint8(0x0B);
+  EmitOperand(reg.LowBits(), address);
+}
+
+
 void X86_64Assembler::orl(CpuRegister dst, const Immediate& imm) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitOptionalRex32(dst);
@@ -1044,6 +1068,14 @@
 }
 
 
+void X86_64Assembler::orq(CpuRegister dst, CpuRegister src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitRex64(dst, src);
+  EmitUint8(0x0B);
+  EmitOperand(dst.LowBits(), Operand(src));
+}
+
+
 void X86_64Assembler::xorl(CpuRegister dst, CpuRegister src) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitOptionalRex32(dst, src);
@@ -1052,6 +1084,21 @@
 }
 
 
+void X86_64Assembler::xorl(CpuRegister reg, const Address& address) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitOptionalRex32(reg, address);
+  EmitUint8(0x33);
+  EmitOperand(reg.LowBits(), address);
+}
+
+
+void X86_64Assembler::xorl(CpuRegister dst, const Immediate& imm) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitOptionalRex32(dst);
+  EmitComplex(6, Operand(dst), imm);
+}
+
+
 void X86_64Assembler::xorq(CpuRegister dst, CpuRegister src) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitRex64(dst, src);
diff --git a/compiler/utils/x86_64/assembler_x86_64.h b/compiler/utils/x86_64/assembler_x86_64.h
index 42d774a..285b4cf 100644
--- a/compiler/utils/x86_64/assembler_x86_64.h
+++ b/compiler/utils/x86_64/assembler_x86_64.h
@@ -398,12 +398,18 @@
 
   void andl(CpuRegister dst, const Immediate& imm);
   void andl(CpuRegister dst, CpuRegister src);
+  void andl(CpuRegister reg, const Address& address);
   void andq(CpuRegister dst, const Immediate& imm);
+  void andq(CpuRegister dst, CpuRegister src);
 
   void orl(CpuRegister dst, const Immediate& imm);
   void orl(CpuRegister dst, CpuRegister src);
+  void orl(CpuRegister reg, const Address& address);
+  void orq(CpuRegister dst, CpuRegister src);
 
   void xorl(CpuRegister dst, CpuRegister src);
+  void xorl(CpuRegister dst, const Immediate& imm);
+  void xorl(CpuRegister reg, const Address& address);
   void xorq(CpuRegister dst, const Immediate& imm);
   void xorq(CpuRegister dst, CpuRegister src);
 
diff --git a/test/411-optimizing-arith/src/Main.java b/test/411-optimizing-arith/src/Main.java
index a22c516..3a5d7c0 100644
--- a/test/411-optimizing-arith/src/Main.java
+++ b/test/411-optimizing-arith/src/Main.java
@@ -101,7 +101,7 @@
     expectEquals(0L, $opt$Mul(3L, 0L));
     expectEquals(-3L, $opt$Mul(1L, -3L));
     expectEquals(36L, $opt$Mul(-12L, -3L));
-    expectEquals(33L, $opt$Mul(1L, 3L) * 11F);
+    expectEquals(33L, $opt$Mul(1L, 3L) * 11L);
     expectEquals(240518168583L, $opt$Mul(34359738369L, 7L)); // (2^35 + 1) * 7
   }
 
diff --git a/test/427-bitwise/expected.txt b/test/427-bitwise/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/427-bitwise/expected.txt
diff --git a/test/427-bitwise/info.txt b/test/427-bitwise/info.txt
new file mode 100644
index 0000000..4762847
--- /dev/null
+++ b/test/427-bitwise/info.txt
@@ -0,0 +1 @@
+Tests for the and/or/xor opcodes.
diff --git a/test/427-bitwise/src/Main.java b/test/427-bitwise/src/Main.java
new file mode 100644
index 0000000..e984066
--- /dev/null
+++ b/test/427-bitwise/src/Main.java
@@ -0,0 +1,233 @@
+/*
+ * 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 result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+
+  public static void expectEquals(long expected, long result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+
+  public static void main(String[] args) {
+    andInt();
+    andLong();
+
+    orInt();
+    orLong();
+
+    xorInt();
+    xorLong();
+  }
+
+  private static void andInt() {
+    expectEquals(1, $opt$And(5, 3));
+    expectEquals(0, $opt$And(0, 0));
+    expectEquals(0, $opt$And(0, 3));
+    expectEquals(0, $opt$And(3, 0));
+    expectEquals(1, $opt$And(1, -3));
+    expectEquals(-12, $opt$And(-12, -3));
+
+    expectEquals(1, $opt$AndLit8(1));
+    expectEquals(0, $opt$AndLit8(0));
+    expectEquals(0, $opt$AndLit8(0));
+    expectEquals(3, $opt$AndLit8(3));
+    expectEquals(4, $opt$AndLit8(-12));
+
+    expectEquals(0, $opt$AndLit16(1));
+    expectEquals(0, $opt$AndLit16(0));
+    expectEquals(0, $opt$AndLit16(0));
+    expectEquals(0, $opt$AndLit16(3));
+    expectEquals(65280, $opt$AndLit16(-12));
+  }
+
+  private static void andLong() {
+    expectEquals(1L, $opt$And(5L, 3L));
+    expectEquals(0L, $opt$And(0L, 0L));
+    expectEquals(0L, $opt$And(0L, 3L));
+    expectEquals(0L, $opt$And(3L, 0L));
+    expectEquals(1L, $opt$And(1L, -3L));
+    expectEquals(-12L, $opt$And(-12L, -3L));
+
+    expectEquals(1L, $opt$AndLit8(1L));
+    expectEquals(0L, $opt$AndLit8(0L));
+    expectEquals(0L, $opt$AndLit8(0L));
+    expectEquals(3L, $opt$AndLit8(3L));
+    expectEquals(4L, $opt$AndLit8(-12L));
+
+    expectEquals(0L, $opt$AndLit16(1L));
+    expectEquals(0L, $opt$AndLit16(0L));
+    expectEquals(0L, $opt$AndLit16(0L));
+    expectEquals(0L, $opt$AndLit16(3L));
+    expectEquals(65280L, $opt$AndLit16(-12L));
+  }
+
+  static int $opt$And(int a, int b) {
+    return a & b;
+  }
+
+  static int $opt$AndLit8(int a) {
+    return a & 0xF;
+  }
+
+  static int $opt$AndLit16(int a) {
+    return a & 0xFF00;
+  }
+
+  static long $opt$And(long a, long b) {
+    return a & b;
+  }
+
+  static long $opt$AndLit8(long a) {
+    return a & 0xF;
+  }
+
+  static long $opt$AndLit16(long a) {
+    return a & 0xFF00;
+  }
+
+  private static void orInt() {
+    expectEquals(7, $opt$Or(5, 3));
+    expectEquals(0, $opt$Or(0, 0));
+    expectEquals(3, $opt$Or(0, 3));
+    expectEquals(3, $opt$Or(3, 0));
+    expectEquals(-3, $opt$Or(1, -3));
+    expectEquals(-3, $opt$Or(-12, -3));
+
+    expectEquals(15, $opt$OrLit8(1));
+    expectEquals(15, $opt$OrLit8(0));
+    expectEquals(15, $opt$OrLit8(3));
+    expectEquals(-1, $opt$OrLit8(-12));
+
+    expectEquals(0xFF01, $opt$OrLit16(1));
+    expectEquals(0xFF00, $opt$OrLit16(0));
+    expectEquals(0xFF03, $opt$OrLit16(3));
+    expectEquals(-12, $opt$OrLit16(-12));
+  }
+
+  private static void orLong() {
+    expectEquals(7L, $opt$Or(5L, 3L));
+    expectEquals(0L, $opt$Or(0L, 0L));
+    expectEquals(3L, $opt$Or(0L, 3L));
+    expectEquals(3L, $opt$Or(3L, 0L));
+    expectEquals(-3L, $opt$Or(1L, -3L));
+    expectEquals(-3L, $opt$Or(-12L, -3L));
+
+    expectEquals(15L, $opt$OrLit8(1L));
+    expectEquals(15L, $opt$OrLit8(0L));
+    expectEquals(15L, $opt$OrLit8(3L));
+    expectEquals(-1L, $opt$OrLit8(-12L));
+
+    expectEquals(0xFF01L, $opt$OrLit16(1L));
+    expectEquals(0xFF00L, $opt$OrLit16(0L));
+    expectEquals(0xFF03L, $opt$OrLit16(3L));
+    expectEquals(-12L, $opt$OrLit16(-12L));
+  }
+
+  static int $opt$Or(int a, int b) {
+    return a | b;
+  }
+
+  static int $opt$OrLit8(int a) {
+    return a | 0xF;
+  }
+
+  static int $opt$OrLit16(int a) {
+    return a | 0xFF00;
+  }
+
+  static long $opt$Or(long a, long b) {
+    return a | b;
+  }
+
+  static long $opt$OrLit8(long a) {
+    return a | 0xF;
+  }
+
+  static long $opt$OrLit16(long a) {
+    return a | 0xFF00;
+  }
+
+  private static void xorInt() {
+    expectEquals(6, $opt$Xor(5, 3));
+    expectEquals(0, $opt$Xor(0, 0));
+    expectEquals(3, $opt$Xor(0, 3));
+    expectEquals(3, $opt$Xor(3, 0));
+    expectEquals(-4, $opt$Xor(1, -3));
+    expectEquals(9, $opt$Xor(-12, -3));
+
+    expectEquals(14, $opt$XorLit8(1));
+    expectEquals(15, $opt$XorLit8(0));
+    expectEquals(12, $opt$XorLit8(3));
+    expectEquals(-5, $opt$XorLit8(-12));
+
+    expectEquals(0xFF01, $opt$XorLit16(1));
+    expectEquals(0xFF00, $opt$XorLit16(0));
+    expectEquals(0xFF03, $opt$XorLit16(3));
+    expectEquals(-0xFF0c, $opt$XorLit16(-12));
+  }
+
+  private static void xorLong() {
+    expectEquals(6L, $opt$Xor(5L, 3L));
+    expectEquals(0L, $opt$Xor(0L, 0L));
+    expectEquals(3L, $opt$Xor(0L, 3L));
+    expectEquals(3L, $opt$Xor(3L, 0L));
+    expectEquals(-4L, $opt$Xor(1L, -3L));
+    expectEquals(9L, $opt$Xor(-12L, -3L));
+
+    expectEquals(14L, $opt$XorLit8(1L));
+    expectEquals(15L, $opt$XorLit8(0L));
+    expectEquals(12L, $opt$XorLit8(3L));
+    expectEquals(-5L, $opt$XorLit8(-12L));
+
+    expectEquals(0xFF01L, $opt$XorLit16(1L));
+    expectEquals(0xFF00L, $opt$XorLit16(0L));
+    expectEquals(0xFF03L, $opt$XorLit16(3L));
+    expectEquals(-0xFF0cL, $opt$XorLit16(-12L));
+  }
+
+  static int $opt$Xor(int a, int b) {
+    return a ^ b;
+  }
+
+  static int $opt$XorLit8(int a) {
+    return a ^ 0xF;
+  }
+
+  static int $opt$XorLit16(int a) {
+    return a ^ 0xFF00;
+  }
+
+  static long $opt$Xor(long a, long b) {
+    return a ^ b;
+  }
+
+  static long $opt$XorLit8(long a) {
+    return a ^ 0xF;
+  }
+
+  static long $opt$XorLit16(long a) {
+    return a ^ 0xFF00;
+  }
+}