Improve Thumb2 bitwise operations.

Allow embedding constants in AND, ORR, EOR. Add ORN to
assembler, use BIC and ORN for AND and ORR when needed.

Change-Id: I24d69ecc7ce6992b9c5eb7a313ff47a942de9661
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index d172fba..dd53882 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -3512,6 +3512,47 @@
   }
 }
 
+Location LocationsBuilderARM::ArmEncodableConstantOrRegister(HInstruction* constant,
+                                                             Opcode opcode) {
+  DCHECK(!Primitive::IsFloatingPointType(constant->GetType()));
+  if (constant->IsConstant() &&
+      CanEncodeConstantAsImmediate(constant->AsConstant(), opcode)) {
+    return Location::ConstantLocation(constant->AsConstant());
+  }
+  return Location::RequiresRegister();
+}
+
+bool LocationsBuilderARM::CanEncodeConstantAsImmediate(HConstant* input_cst,
+                                                       Opcode opcode) {
+  uint64_t value = static_cast<uint64_t>(Int64FromConstant(input_cst));
+  if (Primitive::Is64BitType(input_cst->GetType())) {
+    return CanEncodeConstantAsImmediate(Low32Bits(value), opcode) &&
+        CanEncodeConstantAsImmediate(High32Bits(value), opcode);
+  } else {
+    return CanEncodeConstantAsImmediate(Low32Bits(value), opcode);
+  }
+}
+
+bool LocationsBuilderARM::CanEncodeConstantAsImmediate(uint32_t value, Opcode opcode) {
+  ShifterOperand so;
+  ArmAssembler* assembler = codegen_->GetAssembler();
+  if (assembler->ShifterOperandCanHold(kNoRegister, kNoRegister, opcode, value, &so)) {
+    return true;
+  }
+  Opcode neg_opcode = kNoOperand;
+  switch (opcode) {
+    case AND:
+      neg_opcode = BIC;
+      break;
+    case ORR:
+      neg_opcode = ORN;
+      break;
+    default:
+      return false;
+  }
+  return assembler->ShifterOperandCanHold(kNoRegister, kNoRegister, neg_opcode, ~value, &so);
+}
+
 void InstructionCodeGeneratorARM::HandleFieldGet(HInstruction* instruction,
                                                  const FieldInfo& field_info) {
   DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
@@ -4912,17 +4953,18 @@
       nullptr);
 }
 
-void LocationsBuilderARM::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); }
-void LocationsBuilderARM::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); }
-void LocationsBuilderARM::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); }
+void LocationsBuilderARM::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction, AND); }
+void LocationsBuilderARM::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction, ORR); }
+void LocationsBuilderARM::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction, EOR); }
 
-void LocationsBuilderARM::HandleBitwiseOperation(HBinaryOperation* instruction) {
+void LocationsBuilderARM::HandleBitwiseOperation(HBinaryOperation* instruction, Opcode opcode) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
   DCHECK(instruction->GetResultType() == Primitive::kPrimInt
          || instruction->GetResultType() == Primitive::kPrimLong);
+  // Note: GVN reorders commutative operations to have the constant on the right hand side.
   locations->SetInAt(0, Location::RequiresRegister());
-  locations->SetInAt(1, Location::RequiresRegister());
+  locations->SetInAt(1, ArmEncodableConstantOrRegister(instruction->InputAt(1), opcode));
   locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
 }
 
@@ -4938,48 +4980,131 @@
   HandleBitwiseOperation(instruction);
 }
 
+void InstructionCodeGeneratorARM::GenerateAndConst(Register out, Register first, uint32_t value) {
+  // Optimize special cases for individual halfs of `and-long` (`and` is simplified earlier).
+  if (value == 0xffffffffu) {
+    if (out != first) {
+      __ mov(out, ShifterOperand(first));
+    }
+    return;
+  }
+  if (value == 0u) {
+    __ mov(out, ShifterOperand(0));
+    return;
+  }
+  ShifterOperand so;
+  if (__ ShifterOperandCanHold(kNoRegister, kNoRegister, AND, value, &so)) {
+    __ and_(out, first, so);
+  } else {
+    DCHECK(__ ShifterOperandCanHold(kNoRegister, kNoRegister, BIC, ~value, &so));
+    __ bic(out, first, ShifterOperand(~value));
+  }
+}
+
+void InstructionCodeGeneratorARM::GenerateOrrConst(Register out, Register first, uint32_t value) {
+  // Optimize special cases for individual halfs of `or-long` (`or` is simplified earlier).
+  if (value == 0u) {
+    if (out != first) {
+      __ mov(out, ShifterOperand(first));
+    }
+    return;
+  }
+  if (value == 0xffffffffu) {
+    __ mvn(out, ShifterOperand(0));
+    return;
+  }
+  ShifterOperand so;
+  if (__ ShifterOperandCanHold(kNoRegister, kNoRegister, ORR, value, &so)) {
+    __ orr(out, first, so);
+  } else {
+    DCHECK(__ ShifterOperandCanHold(kNoRegister, kNoRegister, ORN, ~value, &so));
+    __ orn(out, first, ShifterOperand(~value));
+  }
+}
+
+void InstructionCodeGeneratorARM::GenerateEorConst(Register out, Register first, uint32_t value) {
+  // Optimize special case for individual halfs of `xor-long` (`xor` is simplified earlier).
+  if (value == 0u) {
+    if (out != first) {
+      __ mov(out, ShifterOperand(first));
+    }
+    return;
+  }
+  __ eor(out, first, ShifterOperand(value));
+}
+
 void InstructionCodeGeneratorARM::HandleBitwiseOperation(HBinaryOperation* instruction) {
   LocationSummary* locations = instruction->GetLocations();
+  Location first = locations->InAt(0);
+  Location second = locations->InAt(1);
+  Location out = locations->Out();
+
+  if (second.IsConstant()) {
+    uint64_t value = static_cast<uint64_t>(Int64FromConstant(second.GetConstant()));
+    uint32_t value_low = Low32Bits(value);
+    if (instruction->GetResultType() == Primitive::kPrimInt) {
+      Register first_reg = first.AsRegister<Register>();
+      Register out_reg = out.AsRegister<Register>();
+      if (instruction->IsAnd()) {
+        GenerateAndConst(out_reg, first_reg, value_low);
+      } else if (instruction->IsOr()) {
+        GenerateOrrConst(out_reg, first_reg, value_low);
+      } else {
+        DCHECK(instruction->IsXor());
+        GenerateEorConst(out_reg, first_reg, value_low);
+      }
+    } else {
+      DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
+      uint32_t value_high = High32Bits(value);
+      Register first_low = first.AsRegisterPairLow<Register>();
+      Register first_high = first.AsRegisterPairHigh<Register>();
+      Register out_low = out.AsRegisterPairLow<Register>();
+      Register out_high = out.AsRegisterPairHigh<Register>();
+      if (instruction->IsAnd()) {
+        GenerateAndConst(out_low, first_low, value_low);
+        GenerateAndConst(out_high, first_high, value_high);
+      } else if (instruction->IsOr()) {
+        GenerateOrrConst(out_low, first_low, value_low);
+        GenerateOrrConst(out_high, first_high, value_high);
+      } else {
+        DCHECK(instruction->IsXor());
+        GenerateEorConst(out_low, first_low, value_low);
+        GenerateEorConst(out_high, first_high, value_high);
+      }
+    }
+    return;
+  }
 
   if (instruction->GetResultType() == Primitive::kPrimInt) {
-    Register first = locations->InAt(0).AsRegister<Register>();
-    Register second = locations->InAt(1).AsRegister<Register>();
-    Register out = locations->Out().AsRegister<Register>();
+    Register first_reg = first.AsRegister<Register>();
+    ShifterOperand second_reg(second.AsRegister<Register>());
+    Register out_reg = out.AsRegister<Register>();
     if (instruction->IsAnd()) {
-      __ and_(out, first, ShifterOperand(second));
+      __ and_(out_reg, first_reg, second_reg);
     } else if (instruction->IsOr()) {
-      __ orr(out, first, ShifterOperand(second));
+      __ orr(out_reg, first_reg, second_reg);
     } else {
       DCHECK(instruction->IsXor());
-      __ eor(out, first, ShifterOperand(second));
+      __ eor(out_reg, first_reg, second_reg);
     }
   } else {
     DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
-    Location first = locations->InAt(0);
-    Location second = locations->InAt(1);
-    Location out = locations->Out();
+    Register first_low = first.AsRegisterPairLow<Register>();
+    Register first_high = first.AsRegisterPairHigh<Register>();
+    ShifterOperand second_low(second.AsRegisterPairLow<Register>());
+    ShifterOperand second_high(second.AsRegisterPairHigh<Register>());
+    Register out_low = out.AsRegisterPairLow<Register>();
+    Register out_high = out.AsRegisterPairHigh<Register>();
     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>()));
+      __ and_(out_low, first_low, second_low);
+      __ and_(out_high, first_high, second_high);
     } 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>()));
+      __ orr(out_low, first_low, second_low);
+      __ orr(out_high, first_high, second_high);
     } 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>()));
+      __ eor(out_low, first_low, second_low);
+      __ eor(out_high, first_high, second_high);
     }
   }
 }
diff --git a/compiler/optimizing/code_generator_arm.h b/compiler/optimizing/code_generator_arm.h
index 16d1d38..6900933 100644
--- a/compiler/optimizing/code_generator_arm.h
+++ b/compiler/optimizing/code_generator_arm.h
@@ -169,11 +169,15 @@
 
  private:
   void HandleInvoke(HInvoke* invoke);
-  void HandleBitwiseOperation(HBinaryOperation* operation);
+  void HandleBitwiseOperation(HBinaryOperation* operation, Opcode opcode);
   void HandleShift(HBinaryOperation* operation);
   void HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info);
   void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info);
 
+  Location ArmEncodableConstantOrRegister(HInstruction* constant, Opcode opcode);
+  bool CanEncodeConstantAsImmediate(HConstant* input_cst, Opcode opcode);
+  bool CanEncodeConstantAsImmediate(uint32_t value, Opcode opcode);
+
   CodeGeneratorARM* const codegen_;
   InvokeDexCallingConventionVisitorARM parameter_visitor_;
 
@@ -205,6 +209,9 @@
   // the suspend call.
   void GenerateSuspendCheck(HSuspendCheck* check, HBasicBlock* successor);
   void GenerateClassInitializationCheck(SlowPathCode* slow_path, Register class_reg);
+  void GenerateAndConst(Register out, Register first, uint32_t value);
+  void GenerateOrrConst(Register out, Register first, uint32_t value);
+  void GenerateEorConst(Register out, Register first, uint32_t value);
   void HandleBitwiseOperation(HBinaryOperation* operation);
   void HandleShift(HBinaryOperation* operation);
   void GenerateMemoryBarrier(MemBarrierKind kind);
diff --git a/compiler/utils/arm/assembler_arm.h b/compiler/utils/arm/assembler_arm.h
index 967b191..bb77113 100644
--- a/compiler/utils/arm/assembler_arm.h
+++ b/compiler/utils/arm/assembler_arm.h
@@ -470,6 +470,13 @@
     orr(rd, rn, so, cond, kCcSet);
   }
 
+  virtual void orn(Register rd, Register rn, const ShifterOperand& so,
+                   Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
+
+  virtual void orns(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) {
+    orn(rd, rn, so, cond, kCcSet);
+  }
+
   virtual void mov(Register rd, const ShifterOperand& so,
                    Condition cond = AL, SetCc set_cc = kCcDontCare) = 0;
 
diff --git a/compiler/utils/arm/assembler_arm32.cc b/compiler/utils/arm/assembler_arm32.cc
index f7772ae..c6af283 100644
--- a/compiler/utils/arm/assembler_arm32.cc
+++ b/compiler/utils/arm/assembler_arm32.cc
@@ -130,6 +130,15 @@
 }
 
 
+void Arm32Assembler::orn(Register rd ATTRIBUTE_UNUSED,
+                         Register rn ATTRIBUTE_UNUSED,
+                         const ShifterOperand& so ATTRIBUTE_UNUSED,
+                         Condition cond ATTRIBUTE_UNUSED,
+                         SetCc set_cc ATTRIBUTE_UNUSED) {
+  LOG(FATAL) << "orn is not supported on ARM32";
+}
+
+
 void Arm32Assembler::mov(Register rd, const ShifterOperand& so,
                          Condition cond, SetCc set_cc) {
   EmitType01(cond, so.type(), MOV, set_cc, R0, rd, so);
diff --git a/compiler/utils/arm/assembler_arm32.h b/compiler/utils/arm/assembler_arm32.h
index 3407369..d346096 100644
--- a/compiler/utils/arm/assembler_arm32.h
+++ b/compiler/utils/arm/assembler_arm32.h
@@ -74,6 +74,9 @@
   virtual void orr(Register rd, Register rn, const ShifterOperand& so,
                    Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE;
 
+  virtual void orn(Register rd, Register rn, const ShifterOperand& so,
+                   Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE;
+
   virtual void mov(Register rd, const ShifterOperand& so,
                    Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE;
 
diff --git a/compiler/utils/arm/assembler_thumb2.cc b/compiler/utils/arm/assembler_thumb2.cc
index 0f6c4f5..b8c5fd2 100644
--- a/compiler/utils/arm/assembler_thumb2.cc
+++ b/compiler/utils/arm/assembler_thumb2.cc
@@ -410,6 +410,7 @@
     case MOV:
       // TODO: Support less than or equal to 12bits.
       return ArmAssembler::ModifiedImmediate(immediate) != kInvalidModifiedImmediate;
+
     case MVN:
     default:
       return ArmAssembler::ModifiedImmediate(immediate) != kInvalidModifiedImmediate;
@@ -492,6 +493,12 @@
 }
 
 
+void Thumb2Assembler::orn(Register rd, Register rn, const ShifterOperand& so,
+                          Condition cond, SetCc set_cc) {
+  EmitDataProcessing(cond, ORN, set_cc, rn, rd, so);
+}
+
+
 void Thumb2Assembler::mov(Register rd, const ShifterOperand& so,
                           Condition cond, SetCc set_cc) {
   EmitDataProcessing(cond, MOV, set_cc, R0, rd, so);
@@ -1105,6 +1112,7 @@
       rn_is_valid = false;      // There is no Rn for these instructions.
       break;
     case TEQ:
+    case ORN:
       return true;
     case ADD:
     case SUB:
@@ -1222,6 +1230,7 @@
     case MOV: thumb_opcode =  2U /* 0b0010 */; rn = PC; break;
     case BIC: thumb_opcode =  1U /* 0b0001 */; break;
     case MVN: thumb_opcode =  3U /* 0b0011 */; rn = PC; break;
+    case ORN: thumb_opcode =  3U /* 0b0011 */; break;
     default:
       break;
   }
diff --git a/compiler/utils/arm/assembler_thumb2.h b/compiler/utils/arm/assembler_thumb2.h
index a1a8927..584a387 100644
--- a/compiler/utils/arm/assembler_thumb2.h
+++ b/compiler/utils/arm/assembler_thumb2.h
@@ -98,6 +98,9 @@
   virtual void orr(Register rd, Register rn, const ShifterOperand& so,
                    Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE;
 
+  virtual void orn(Register rd, Register rn, const ShifterOperand& so,
+                   Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE;
+
   virtual void mov(Register rd, const ShifterOperand& so,
                    Condition cond = AL, SetCc set_cc = kCcDontCare) OVERRIDE;
 
diff --git a/compiler/utils/arm/constants_arm.h b/compiler/utils/arm/constants_arm.h
index 6b4daed..2060064 100644
--- a/compiler/utils/arm/constants_arm.h
+++ b/compiler/utils/arm/constants_arm.h
@@ -148,7 +148,8 @@
   MOV = 13,  // Move
   BIC = 14,  // Bit Clear
   MVN = 15,  // Move Not
-  kMaxOperand = 16
+  ORN = 16,  // Logical OR NOT.
+  kMaxOperand = 17
 };
 std::ostream& operator<<(std::ostream& os, const Opcode& rhs);
 
diff --git a/compiler/utils/assembler_thumb_test.cc b/compiler/utils/assembler_thumb_test.cc
index b2a354b..2ae8841 100644
--- a/compiler/utils/assembler_thumb_test.cc
+++ b/compiler/utils/assembler_thumb_test.cc
@@ -238,6 +238,7 @@
   __ sub(R0, R1, ShifterOperand(R2), AL, kCcKeep);
   __ and_(R0, R1, ShifterOperand(R2), AL, kCcKeep);
   __ orr(R0, R1, ShifterOperand(R2), AL, kCcKeep);
+  __ orn(R0, R1, ShifterOperand(R2), AL, kCcKeep);
   __ eor(R0, R1, ShifterOperand(R2), AL, kCcKeep);
   __ bic(R0, R1, ShifterOperand(R2), AL, kCcKeep);
   __ adc(R0, R1, ShifterOperand(R2), AL, kCcKeep);
@@ -371,6 +372,7 @@
   __ sub(R0, R1, ShifterOperand(0x55));
   __ and_(R0, R1, ShifterOperand(0x55));
   __ orr(R0, R1, ShifterOperand(0x55));
+  __ orn(R0, R1, ShifterOperand(0x55));
   __ eor(R0, R1, ShifterOperand(0x55));
   __ bic(R0, R1, ShifterOperand(0x55));
   __ adc(R0, R1, ShifterOperand(0x55));
@@ -403,6 +405,7 @@
   __ sub(R0, R1, ShifterOperand(0x550055));
   __ and_(R0, R1, ShifterOperand(0x550055));
   __ orr(R0, R1, ShifterOperand(0x550055));
+  __ orn(R0, R1, ShifterOperand(0x550055));
   __ eor(R0, R1, ShifterOperand(0x550055));
   __ bic(R0, R1, ShifterOperand(0x550055));
   __ adc(R0, R1, ShifterOperand(0x550055));
diff --git a/compiler/utils/assembler_thumb_test_expected.cc.inc b/compiler/utils/assembler_thumb_test_expected.cc.inc
index 82ad642..b79c2e4 100644
--- a/compiler/utils/assembler_thumb_test_expected.cc.inc
+++ b/compiler/utils/assembler_thumb_test_expected.cc.inc
@@ -23,109 +23,110 @@
   "   8:	eba1 0002 	sub.w	r0, r1, r2\n",
   "   c:	ea01 0002 	and.w	r0, r1, r2\n",
   "  10:	ea41 0002 	orr.w	r0, r1, r2\n",
-  "  14:	ea81 0002 	eor.w	r0, r1, r2\n",
-  "  18:	ea21 0002 	bic.w	r0, r1, r2\n",
-  "  1c:	eb41 0002 	adc.w	r0, r1, r2\n",
-  "  20:	eb61 0002 	sbc.w	r0, r1, r2\n",
-  "  24:	ebc1 0002 	rsb	r0, r1, r2\n",
-  "  28:	ea90 0f01 	teq	r0, r1\n",
-  "  2c:	0008      	movs	r0, r1\n",
-  "  2e:	4608      	mov	r0, r1\n",
-  "  30:	43c8      	mvns	r0, r1\n",
-  "  32:	4408      	add	r0, r1\n",
-  "  34:	1888      	adds	r0, r1, r2\n",
-  "  36:	1a88      	subs	r0, r1, r2\n",
-  "  38:	4148      	adcs	r0, r1\n",
-  "  3a:	4188      	sbcs	r0, r1\n",
-  "  3c:	4008      	ands	r0, r1\n",
-  "  3e:	4308      	orrs	r0, r1\n",
-  "  40:	4048      	eors	r0, r1\n",
-  "  42:	4388      	bics	r0, r1\n",
-  "  44:	4208      	tst	r0, r1\n",
-  "  46:	4288      	cmp	r0, r1\n",
-  "  48:	42c8      	cmn	r0, r1\n",
-  "  4a:	4641		mov	r1, r8\n",
-  "  4c:	4681		mov	r9, r0\n",
-  "  4e:	46c8		mov	r8, r9\n",
-  "  50:	4441		add	r1, r8\n",
-  "  52:	4481		add	r9, r0\n",
-  "  54:	44c8		add	r8, r9\n",
-  "  56:	4548		cmp	r0, r9\n",
-  "  58:	4588		cmp	r8, r1\n",
-  "  5a:	45c1		cmp	r9, r8\n",
-  "  5c:	4248   	   	negs	r0, r1\n",
-  "  5e:	4240   	   	negs	r0, r0\n",
-  "  60:	ea5f 0008  	movs.w	r0, r8\n",
-  "  64:	ea7f 0008  	mvns.w	r0, r8\n",
-  "  68:	eb01 0008 	add.w	r0, r1, r8\n",
-  "  6c:	eb11 0008 	adds.w	r0, r1, r8\n",
-  "  70:	ebb1 0008 	subs.w	r0, r1, r8\n",
-  "  74:	eb50 0008 	adcs.w	r0, r0, r8\n",
-  "  78:	eb70 0008 	sbcs.w	r0, r0, r8\n",
-  "  7c:	ea10 0008 	ands.w	r0, r0, r8\n",
-  "  80:	ea50 0008 	orrs.w	r0, r0, r8\n",
-  "  84:	ea90 0008 	eors.w	r0, r0, r8\n",
-  "  88:	ea30 0008 	bics.w	r0, r0, r8\n",
-  "  8c:	ea10 0f08 	tst.w	r0, r8\n",
-  "  90:	eb10 0f08 	cmn.w	r0, r8\n",
-  "  94:	f1d8 0000 	rsbs	r0, r8, #0\n",
-  "  98:	f1d8 0800 	rsbs	r8, r8, #0\n",
-  "  9c:	bf08       	it	eq\n",
-  "  9e:	ea7f 0001  	mvnseq.w	r0, r1\n",
-  "  a2:	bf08       	it	eq\n",
-  "  a4:	eb11 0002 	addseq.w	r0, r1, r2\n",
-  "  a8:	bf08       	it	eq\n",
-  "  aa:	ebb1 0002 	subseq.w	r0, r1, r2\n",
-  "  ae:	bf08       	it	eq\n",
-  "  b0:	eb50 0001 	adcseq.w	r0, r0, r1\n",
-  "  b4:	bf08       	it	eq\n",
-  "  b6:	eb70 0001 	sbcseq.w	r0, r0, r1\n",
-  "  ba:	bf08       	it	eq\n",
-  "  bc:	ea10 0001 	andseq.w	r0, r0, r1\n",
-  "  c0:	bf08       	it	eq\n",
-  "  c2:	ea50 0001 	orrseq.w	r0, r0, r1\n",
-  "  c6:	bf08       	it	eq\n",
-  "  c8:	ea90 0001 	eorseq.w	r0, r0, r1\n",
-  "  cc:	bf08       	it	eq\n",
-  "  ce:	ea30 0001 	bicseq.w	r0, r0, r1\n",
-  "  d2:	bf08       	it	eq\n",
-  "  d4:	43c8      	mvneq	r0, r1\n",
+  "  14:	ea61 0002 	orn	r0, r1, r2\n",
+  "  18:	ea81 0002 	eor.w	r0, r1, r2\n",
+  "  1c:	ea21 0002 	bic.w	r0, r1, r2\n",
+  "  20:	eb41 0002 	adc.w	r0, r1, r2\n",
+  "  24:	eb61 0002 	sbc.w	r0, r1, r2\n",
+  "  28:	ebc1 0002 	rsb	r0, r1, r2\n",
+  "  2c:	ea90 0f01 	teq	r0, r1\n",
+  "  30:	0008      	movs	r0, r1\n",
+  "  32:	4608      	mov	r0, r1\n",
+  "  34:	43c8      	mvns	r0, r1\n",
+  "  36:	4408      	add	r0, r1\n",
+  "  38:	1888      	adds	r0, r1, r2\n",
+  "  3a:	1a88      	subs	r0, r1, r2\n",
+  "  3c:	4148      	adcs	r0, r1\n",
+  "  3e:	4188      	sbcs	r0, r1\n",
+  "  40:	4008      	ands	r0, r1\n",
+  "  42:	4308      	orrs	r0, r1\n",
+  "  44:	4048      	eors	r0, r1\n",
+  "  46:	4388      	bics	r0, r1\n",
+  "  48:	4208      	tst	r0, r1\n",
+  "  4a:	4288      	cmp	r0, r1\n",
+  "  4c:	42c8      	cmn	r0, r1\n",
+  "  4e:	4641		mov	r1, r8\n",
+  "  50:	4681		mov	r9, r0\n",
+  "  52:	46c8		mov	r8, r9\n",
+  "  54:	4441		add	r1, r8\n",
+  "  56:	4481		add	r9, r0\n",
+  "  58:	44c8		add	r8, r9\n",
+  "  5a:	4548		cmp	r0, r9\n",
+  "  5c:	4588		cmp	r8, r1\n",
+  "  5e:	45c1		cmp	r9, r8\n",
+  "  60:	4248   	   	negs	r0, r1\n",
+  "  62:	4240   	   	negs	r0, r0\n",
+  "  64:	ea5f 0008  	movs.w	r0, r8\n",
+  "  68:	ea7f 0008  	mvns.w	r0, r8\n",
+  "  6c:	eb01 0008 	add.w	r0, r1, r8\n",
+  "  70:	eb11 0008 	adds.w	r0, r1, r8\n",
+  "  74:	ebb1 0008 	subs.w	r0, r1, r8\n",
+  "  78:	eb50 0008 	adcs.w	r0, r0, r8\n",
+  "  7c:	eb70 0008 	sbcs.w	r0, r0, r8\n",
+  "  80:	ea10 0008 	ands.w	r0, r0, r8\n",
+  "  84:	ea50 0008 	orrs.w	r0, r0, r8\n",
+  "  88:	ea90 0008 	eors.w	r0, r0, r8\n",
+  "  8c:	ea30 0008 	bics.w	r0, r0, r8\n",
+  "  90:	ea10 0f08 	tst.w	r0, r8\n",
+  "  94:	eb10 0f08 	cmn.w	r0, r8\n",
+  "  98:	f1d8 0000 	rsbs	r0, r8, #0\n",
+  "  9c:	f1d8 0800 	rsbs	r8, r8, #0\n",
+  "  a0:	bf08       	it	eq\n",
+  "  a2:	ea7f 0001  	mvnseq.w	r0, r1\n",
+  "  a6:	bf08       	it	eq\n",
+  "  a8:	eb11 0002 	addseq.w	r0, r1, r2\n",
+  "  ac:	bf08       	it	eq\n",
+  "  ae:	ebb1 0002 	subseq.w	r0, r1, r2\n",
+  "  b2:	bf08       	it	eq\n",
+  "  b4:	eb50 0001 	adcseq.w	r0, r0, r1\n",
+  "  b8:	bf08       	it	eq\n",
+  "  ba:	eb70 0001 	sbcseq.w	r0, r0, r1\n",
+  "  be:	bf08       	it	eq\n",
+  "  c0:	ea10 0001 	andseq.w	r0, r0, r1\n",
+  "  c4:	bf08       	it	eq\n",
+  "  c6:	ea50 0001 	orrseq.w	r0, r0, r1\n",
+  "  ca:	bf08       	it	eq\n",
+  "  cc:	ea90 0001 	eorseq.w	r0, r0, r1\n",
+  "  d0:	bf08       	it	eq\n",
+  "  d2:	ea30 0001 	bicseq.w	r0, r0, r1\n",
   "  d6:	bf08       	it	eq\n",
-  "  d8:	1888      	addeq	r0, r1, r2\n",
+  "  d8:	43c8      	mvneq	r0, r1\n",
   "  da:	bf08       	it	eq\n",
-  "  dc:	1a88      	subeq	r0, r1, r2\n",
+  "  dc:	1888      	addeq	r0, r1, r2\n",
   "  de:	bf08       	it	eq\n",
-  "  e0:	4148      	adceq	r0, r1\n",
+  "  e0:	1a88      	subeq	r0, r1, r2\n",
   "  e2:	bf08       	it	eq\n",
-  "  e4:	4188      	sbceq	r0, r1\n",
+  "  e4:	4148      	adceq	r0, r1\n",
   "  e6:	bf08       	it	eq\n",
-  "  e8:	4008      	andeq	r0, r1\n",
+  "  e8:	4188      	sbceq	r0, r1\n",
   "  ea:	bf08       	it	eq\n",
-  "  ec:	4308      	orreq	r0, r1\n",
+  "  ec:	4008      	andeq	r0, r1\n",
   "  ee:	bf08       	it	eq\n",
-  "  f0:	4048      	eoreq	r0, r1\n",
+  "  f0:	4308      	orreq	r0, r1\n",
   "  f2:	bf08       	it	eq\n",
-  "  f4:	4388      	biceq	r0, r1\n",
-  "  f6:	4608      	mov	r0, r1\n",
-  "  f8:	43c8      	mvns	r0, r1\n",
-  "  fa:	4408      	add	r0, r1\n",
-  "  fc:	1888      	adds	r0, r1, r2\n",
-  "  fe:	1a88      	subs	r0, r1, r2\n",
-  " 100:	4148      	adcs	r0, r1\n",
-  " 102:	4188      	sbcs	r0, r1\n",
-  " 104:	4008      	ands	r0, r1\n",
-  " 106:	4308      	orrs	r0, r1\n",
-  " 108:	4048      	eors	r0, r1\n",
-  " 10a:	4388      	bics	r0, r1\n",
-  " 10c:	4641		mov	r1, r8\n",
-  " 10e:	4681		mov	r9, r0\n",
-  " 110:	46c8		mov	r8, r9\n",
-  " 112:	4441		add	r1, r8\n",
-  " 114:	4481		add	r9, r0\n",
-  " 116:	44c8		add	r8, r9\n",
-  " 118:	4248   	   	negs	r0, r1\n",
-  " 11a:	4240   	   	negs	r0, r0\n",
-  " 11c:	eb01 0c00 	add.w	ip, r1, r0\n",
+  "  f4:	4048      	eoreq	r0, r1\n",
+  "  f6:	bf08       	it	eq\n",
+  "  f8:	4388      	biceq	r0, r1\n",
+  "  fa:	4608      	mov	r0, r1\n",
+  "  fc:	43c8      	mvns	r0, r1\n",
+  "  fe:	4408      	add	r0, r1\n",
+  " 100:	1888      	adds	r0, r1, r2\n",
+  " 102:	1a88      	subs	r0, r1, r2\n",
+  " 104:	4148      	adcs	r0, r1\n",
+  " 106:	4188      	sbcs	r0, r1\n",
+  " 108:	4008      	ands	r0, r1\n",
+  " 10a:	4308      	orrs	r0, r1\n",
+  " 10c:	4048      	eors	r0, r1\n",
+  " 10e:	4388      	bics	r0, r1\n",
+  " 110:	4641		mov	r1, r8\n",
+  " 112:	4681		mov	r9, r0\n",
+  " 114:	46c8		mov	r8, r9\n",
+  " 116:	4441		add	r1, r8\n",
+  " 118:	4481		add	r9, r0\n",
+  " 11a:	44c8		add	r8, r9\n",
+  " 11c:	4248   	   	negs	r0, r1\n",
+  " 11e:	4240   	   	negs	r0, r0\n",
+  " 120:	eb01 0c00 	add.w	ip, r1, r0\n",
   nullptr
 };
 const char* DataProcessingImmediateResults[] = {
@@ -135,21 +136,22 @@
   "   a:	f2a1 0055 	subw	r0, r1, #85	; 0x55\n",
   "   e:	f001 0055 	and.w	r0, r1, #85	; 0x55\n",
   "  12:	f041 0055 	orr.w	r0, r1, #85	; 0x55\n",
-  "  16:	f081 0055 	eor.w	r0, r1, #85	; 0x55\n",
-  "  1a:	f021 0055 	bic.w	r0, r1, #85	; 0x55\n",
-  "  1e:	f141 0055 	adc.w	r0, r1, #85	; 0x55\n",
-  "  22:	f161 0055 	sbc.w	r0, r1, #85	; 0x55\n",
-  "  26:	f1c1 0055 	rsb	r0, r1, #85	; 0x55\n",
-  "  2a:	f010 0f55 	tst.w	r0, #85	; 0x55\n",
-  "  2e:	f090 0f55 	teq	r0, #85	; 0x55\n",
-  "  32:	2855      	cmp	r0, #85	; 0x55\n",
-  "  34:	f110 0f55 	cmn.w	r0, #85	; 0x55\n",
-  "  38:	1d48      	adds	r0, r1, #5\n",
-  "  3a:	1f48      	subs	r0, r1, #5\n",
-  "  3c:	2055      	movs	r0, #85	; 0x55\n",
-  "  3e:	f07f 0055 	mvns.w	r0, #85	; 0x55\n",
-  "  42:	1d48      	adds  r0, r1, #5\n",
-  "  44:	1f48      	subs  r0, r1, #5\n",
+  "  16:	f061 0055 	orn	r0, r1, #85	; 0x55\n",
+  "  1a:	f081 0055 	eor.w	r0, r1, #85	; 0x55\n",
+  "  1e:	f021 0055 	bic.w	r0, r1, #85	; 0x55\n",
+  "  22:	f141 0055 	adc.w	r0, r1, #85	; 0x55\n",
+  "  26:	f161 0055 	sbc.w	r0, r1, #85	; 0x55\n",
+  "  2a:	f1c1 0055 	rsb	r0, r1, #85	; 0x55\n",
+  "  2e:	f010 0f55 	tst.w	r0, #85	; 0x55\n",
+  "  32:	f090 0f55 	teq	r0, #85	; 0x55\n",
+  "  36:	2855      	cmp	r0, #85	; 0x55\n",
+  "  38:	f110 0f55 	cmn.w	r0, #85	; 0x55\n",
+  "  3c:	1d48      	adds	r0, r1, #5\n",
+  "  3e:	1f48      	subs	r0, r1, #5\n",
+  "  40:	2055      	movs	r0, #85	; 0x55\n",
+  "  42:	f07f 0055 	mvns.w	r0, #85	; 0x55\n",
+  "  46:	1d48      	adds	r0, r1, #5\n",
+  "  48:	1f48      	subs	r0, r1, #5\n",
   nullptr
 };
 const char* DataProcessingModifiedImmediateResults[] = {
@@ -159,15 +161,16 @@
   "   c:	f1a1 1055 	sub.w	r0, r1, #5570645	; 0x550055\n",
   "  10:	f001 1055 	and.w	r0, r1, #5570645	; 0x550055\n",
   "  14:	f041 1055 	orr.w	r0, r1, #5570645	; 0x550055\n",
-  "  18:	f081 1055 	eor.w	r0, r1, #5570645	; 0x550055\n",
-  "  1c:	f021 1055 	bic.w	r0, r1, #5570645	; 0x550055\n",
-  "  20:	f141 1055 	adc.w	r0, r1, #5570645	; 0x550055\n",
-  "  24:	f161 1055 	sbc.w	r0, r1, #5570645	; 0x550055\n",
-  "  28:	f1c1 1055 	rsb	r0, r1, #5570645	; 0x550055\n",
-  "  2c:	f010 1f55 	tst.w	r0, #5570645	; 0x550055\n",
-  "  30:	f090 1f55 	teq	r0, #5570645	; 0x550055\n",
-  "  34:	f1b0 1f55 	cmp.w	r0, #5570645	; 0x550055\n",
-  "  38:	f110 1f55 	cmn.w	r0, #5570645	; 0x550055\n",
+  "  18:	f061 1055 	orn	r0, r1, #5570645	; 0x550055\n",
+  "  1c:	f081 1055 	eor.w	r0, r1, #5570645	; 0x550055\n",
+  "  20:	f021 1055 	bic.w	r0, r1, #5570645	; 0x550055\n",
+  "  24:	f141 1055 	adc.w	r0, r1, #5570645	; 0x550055\n",
+  "  28:	f161 1055 	sbc.w	r0, r1, #5570645	; 0x550055\n",
+  "  2c:	f1c1 1055 	rsb	r0, r1, #5570645	; 0x550055\n",
+  "  30:	f010 1f55 	tst.w	r0, #5570645	; 0x550055\n",
+  "  34:	f090 1f55 	teq	r0, #5570645	; 0x550055\n",
+  "  38:	f1b0 1f55 	cmp.w	r0, #5570645	; 0x550055\n",
+  "  3c:	f110 1f55 	cmn.w	r0, #5570645	; 0x550055\n",
   nullptr
 };
 const char* DataProcessingModifiedImmediatesResults[] = {
diff --git a/test/538-checker-embed-constants/expected.txt b/test/538-checker-embed-constants/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/538-checker-embed-constants/expected.txt
diff --git a/test/538-checker-embed-constants/info.txt b/test/538-checker-embed-constants/info.txt
new file mode 100644
index 0000000..5a722ec
--- /dev/null
+++ b/test/538-checker-embed-constants/info.txt
@@ -0,0 +1 @@
+Test embedding of constants in assembler instructions.
diff --git a/test/538-checker-embed-constants/src/Main.java b/test/538-checker-embed-constants/src/Main.java
new file mode 100644
index 0000000..d8618e3
--- /dev/null
+++ b/test/538-checker-embed-constants/src/Main.java
@@ -0,0 +1,290 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+public class Main {
+
+  public static void assertIntEquals(int expected, int result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+
+  public static void assertLongEquals(long expected, long result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+
+  /// CHECK-START-ARM: int Main.and255(int) disassembly (after)
+  /// CHECK-NOT:            movs {{r\d+}}, #255
+  /// CHECK:                and {{r\d+}}, {{r\d+}}, #255
+
+  public static int and255(int arg) {
+    return arg & 255;
+  }
+
+  /// CHECK-START-ARM: int Main.and511(int) disassembly (after)
+  /// CHECK:                movw {{r\d+}}, #511
+  /// CHECK:                and{{(\.w)?}} {{r\d+}}, {{r\d+}}, {{r\d+}}
+
+  public static int and511(int arg) {
+    return arg & 511;
+  }
+
+  /// CHECK-START-ARM: int Main.andNot15(int) disassembly (after)
+  /// CHECK-NOT:            mvn {{r\d+}}, #15
+  /// CHECK:                bic {{r\d+}}, {{r\d+}}, #15
+
+  public static int andNot15(int arg) {
+    return arg & ~15;
+  }
+
+  /// CHECK-START-ARM: int Main.or255(int) disassembly (after)
+  /// CHECK-NOT:            movs {{r\d+}}, #255
+  /// CHECK:                orr {{r\d+}}, {{r\d+}}, #255
+
+  public static int or255(int arg) {
+    return arg | 255;
+  }
+
+  /// CHECK-START-ARM: int Main.or511(int) disassembly (after)
+  /// CHECK:                movw {{r\d+}}, #511
+  /// CHECK:                orr{{(\.w)?}} {{r\d+}}, {{r\d+}}, {{r\d+}}
+
+  public static int or511(int arg) {
+    return arg | 511;
+  }
+
+  /// CHECK-START-ARM: int Main.orNot15(int) disassembly (after)
+  /// CHECK-NOT:            mvn {{r\d+}}, #15
+  /// CHECK:                orn {{r\d+}}, {{r\d+}}, #15
+
+  public static int orNot15(int arg) {
+    return arg | ~15;
+  }
+
+  /// CHECK-START-ARM: int Main.xor255(int) disassembly (after)
+  /// CHECK-NOT:            movs {{r\d+}}, #255
+  /// CHECK:                eor {{r\d+}}, {{r\d+}}, #255
+
+  public static int xor255(int arg) {
+    return arg ^ 255;
+  }
+
+  /// CHECK-START-ARM: int Main.xor511(int) disassembly (after)
+  /// CHECK:                movw {{r\d+}}, #511
+  /// CHECK:                eor{{(\.w)?}} {{r\d+}}, {{r\d+}}, {{r\d+}}
+
+  public static int xor511(int arg) {
+    return arg ^ 511;
+  }
+
+  /// CHECK-START-ARM: int Main.xorNot15(int) disassembly (after)
+  /// CHECK:                mvn {{r\d+}}, #15
+  /// CHECK:                eor{{(\.w)?}} {{r\d+}}, {{r\d+}}, {{r\d+}}
+
+  public static int xorNot15(int arg) {
+    return arg ^ ~15;
+  }
+
+  /// CHECK-START-ARM: long Main.and255(long) disassembly (after)
+  /// CHECK-NOT:            movs {{r\d+}}, #255
+  /// CHECK-NOT:            and
+  /// CHECK-NOT:            bic
+  /// CHECK-DAG:            and {{r\d+}}, {{r\d+}}, #255
+  /// CHECK-DAG:            movs {{r\d+}}, #0
+  /// CHECK-NOT:            and
+  /// CHECK-NOT:            bic
+
+  public static long and255(long arg) {
+    return arg & 255L;
+  }
+
+  /// CHECK-START-ARM: long Main.and511(long) disassembly (after)
+  /// CHECK:                movw {{r\d+}}, #511
+  /// CHECK-NOT:            and
+  /// CHECK-NOT:            bic
+  /// CHECK-DAG:            and{{(\.w)?}} {{r\d+}}, {{r\d+}}, {{r\d+}}
+  /// CHECK-DAG:            movs {{r\d+}}, #0
+  /// CHECK-NOT:            and
+  /// CHECK-NOT:            bic
+
+  public static long and511(long arg) {
+    return arg & 511L;
+  }
+
+  /// CHECK-START-ARM: long Main.andNot15(long) disassembly (after)
+  /// CHECK-NOT:            mvn {{r\d+}}, #15
+  /// CHECK-NOT:            and
+  /// CHECK-NOT:            bic
+  /// CHECK:                bic {{r\d+}}, {{r\d+}}, #15
+  /// CHECK-NOT:            and
+  /// CHECK-NOT:            bic
+
+  public static long andNot15(long arg) {
+    return arg & ~15L;
+  }
+
+  /// CHECK-START-ARM: long Main.and0xfffffff00000000f(long) disassembly (after)
+  /// CHECK-NOT:            movs {{r\d+}}, #15
+  /// CHECK-NOT:            mvn {{r\d+}}, #15
+  /// CHECK-NOT:            and
+  /// CHECK-NOT:            bic
+  /// CHECK-DAG:            and {{r\d+}}, {{r\d+}}, #15
+  /// CHECK-DAG:            bic {{r\d+}}, {{r\d+}}, #15
+  /// CHECK-NOT:            and
+  /// CHECK-NOT:            bic
+
+  public static long and0xfffffff00000000f(long arg) {
+    return arg & 0xfffffff00000000fL;
+  }
+
+  /// CHECK-START-ARM: long Main.or255(long) disassembly (after)
+  /// CHECK-NOT:            movs {{r\d+}}, #255
+  /// CHECK-NOT:            orr
+  /// CHECK-NOT:            orn
+  /// CHECK:                orr {{r\d+}}, {{r\d+}}, #255
+  /// CHECK-NOT:            orr
+  /// CHECK-NOT:            orn
+
+  public static long or255(long arg) {
+    return arg | 255L;
+  }
+
+  /// CHECK-START-ARM: long Main.or511(long) disassembly (after)
+  /// CHECK:                movw {{r\d+}}, #511
+  /// CHECK-NOT:            orr
+  /// CHECK-NOT:            orn
+  /// CHECK:                orr{{(\.w)?}} {{r\d+}}, {{r\d+}}, {{r\d+}}
+  /// CHECK-NOT:            orr
+  /// CHECK-NOT:            orn
+
+  public static long or511(long arg) {
+    return arg | 511L;
+  }
+
+  /// CHECK-START-ARM: long Main.orNot15(long) disassembly (after)
+  /// CHECK-NOT:            mvn {{r\d+}}, #15
+  /// CHECK-NOT:            orr
+  /// CHECK-NOT:            orn
+  /// CHECK-DAG:            orn {{r\d+}}, {{r\d+}}, #15
+  /// CHECK-DAG:            mvn {{r\d+}}, #0
+  /// CHECK-NOT:            orr
+  /// CHECK-NOT:            orn
+
+  public static long orNot15(long arg) {
+    return arg | ~15L;
+  }
+
+  /// CHECK-START-ARM: long Main.or0xfffffff00000000f(long) disassembly (after)
+  /// CHECK-NOT:            movs {{r\d+}}, #15
+  /// CHECK-NOT:            mvn {{r\d+}}, #15
+  /// CHECK-NOT:            orr
+  /// CHECK-NOT:            orn
+  /// CHECK-DAG:            orr {{r\d+}}, {{r\d+}}, #15
+  /// CHECK-DAG:            orn {{r\d+}}, {{r\d+}}, #15
+  /// CHECK-NOT:            orr
+  /// CHECK-NOT:            orn
+
+  public static long or0xfffffff00000000f(long arg) {
+    return arg | 0xfffffff00000000fL;
+  }
+
+  /// CHECK-START-ARM: long Main.xor255(long) disassembly (after)
+  /// CHECK-NOT:            movs {{r\d+}}, #255
+  /// CHECK-NOT:            eor
+  /// CHECK:                eor {{r\d+}}, {{r\d+}}, #255
+  /// CHECK-NOT:            eor
+
+  public static long xor255(long arg) {
+    return arg ^ 255L;
+  }
+
+  /// CHECK-START-ARM: long Main.xor511(long) disassembly (after)
+  /// CHECK:                movw {{r\d+}}, #511
+  /// CHECK-NOT:            eor
+  /// CHECK-DAG:            eor{{(\.w)?}} {{r\d+}}, {{r\d+}}, {{r\d+}}
+  /// CHECK-NOT:            eor
+
+  public static long xor511(long arg) {
+    return arg ^ 511L;
+  }
+
+  /// CHECK-START-ARM: long Main.xorNot15(long) disassembly (after)
+  /// CHECK-DAG:            mvn {{r\d+}}, #15
+  /// CHECK-DAG:            mov.w {{r\d+}}, #-1
+  /// CHECK-NOT:            eor
+  /// CHECK-DAG:            eor{{(\.w)?}} {{r\d+}}, {{r\d+}}, {{r\d+}}
+  /// CHECK-DAG:            eor{{(\.w)?}} {{r\d+}}, {{r\d+}}, {{r\d+}}
+  /// CHECK-NOT:            eor
+
+  public static long xorNot15(long arg) {
+    return arg ^ ~15L;
+  }
+
+  // Note: No support for partial long constant embedding.
+  /// CHECK-START-ARM: long Main.xor0xfffffff00000000f(long) disassembly (after)
+  /// CHECK-DAG:            movs {{r\d+}}, #15
+  /// CHECK-DAG:            mvn {{r\d+}}, #15
+  /// CHECK-NOT:            eor
+  /// CHECK-DAG:            eor{{(\.w)?}} {{r\d+}}, {{r\d+}}, {{r\d+}}
+  /// CHECK-DAG:            eor{{(\.w)?}} {{r\d+}}, {{r\d+}}, {{r\d+}}
+  /// CHECK-NOT:            eor
+
+  public static long xor0xfffffff00000000f(long arg) {
+    return arg ^ 0xfffffff00000000fL;
+  }
+
+  /// CHECK-START-ARM: long Main.xor0xf00000000000000f(long) disassembly (after)
+  /// CHECK-NOT:            movs {{r\d+}}, #15
+  /// CHECK-NOT:            mov.w {{r\d+}}, #-268435456
+  /// CHECK-NOT:            eor
+  /// CHECK-DAG:            eor {{r\d+}}, {{r\d+}}, #15
+  /// CHECK-DAG:            eor {{r\d+}}, {{r\d+}}, #-268435456
+  /// CHECK-NOT:            eor
+
+  public static long xor0xf00000000000000f(long arg) {
+    return arg ^ 0xf00000000000000fL;
+  }
+
+  public static void main(String[] args) {
+    int arg = 0x87654321;
+    assertIntEquals(and255(arg), 0x21);
+    assertIntEquals(and511(arg), 0x121);
+    assertIntEquals(andNot15(arg), 0x87654320);
+    assertIntEquals(or255(arg), 0x876543ff);
+    assertIntEquals(or511(arg), 0x876543ff);
+    assertIntEquals(orNot15(arg), 0xfffffff1);
+    assertIntEquals(xor255(arg), 0x876543de);
+    assertIntEquals(xor511(arg), 0x876542de);
+    assertIntEquals(xorNot15(arg), 0x789abcd1);
+
+    long longArg = 0x1234567887654321L;
+    assertLongEquals(and255(longArg), 0x21L);
+    assertLongEquals(and511(longArg), 0x121L);
+    assertLongEquals(andNot15(longArg), 0x1234567887654320L);
+    assertLongEquals(and0xfffffff00000000f(longArg), 0x1234567000000001L);
+    assertLongEquals(or255(longArg), 0x12345678876543ffL);
+    assertLongEquals(or511(longArg), 0x12345678876543ffL);
+    assertLongEquals(orNot15(longArg), 0xfffffffffffffff1L);
+    assertLongEquals(or0xfffffff00000000f(longArg), 0xfffffff88765432fL);
+    assertLongEquals(xor255(longArg), 0x12345678876543deL);
+    assertLongEquals(xor511(longArg), 0x12345678876542deL);
+    assertLongEquals(xorNot15(longArg), 0xedcba987789abcd1L);
+    assertLongEquals(xor0xfffffff00000000f(longArg), 0xedcba9888765432eL);
+    assertLongEquals(xor0xf00000000000000f(longArg), 0xe23456788765432eL);
+  }
+}