diff options
-rw-r--r-- | compiler/optimizing/code_generator_arm.cc | 189 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_arm.h | 9 | ||||
-rw-r--r-- | compiler/utils/arm/assembler_arm.h | 7 | ||||
-rw-r--r-- | compiler/utils/arm/assembler_arm32.cc | 9 | ||||
-rw-r--r-- | compiler/utils/arm/assembler_arm32.h | 3 | ||||
-rw-r--r-- | compiler/utils/arm/assembler_thumb2.cc | 9 | ||||
-rw-r--r-- | compiler/utils/arm/assembler_thumb2.h | 3 | ||||
-rw-r--r-- | compiler/utils/arm/constants_arm.h | 3 | ||||
-rw-r--r-- | compiler/utils/assembler_thumb_test.cc | 3 | ||||
-rw-r--r-- | compiler/utils/assembler_thumb_test_expected.cc.inc | 241 | ||||
-rw-r--r-- | test/538-checker-embed-constants/expected.txt | 0 | ||||
-rw-r--r-- | test/538-checker-embed-constants/info.txt | 1 | ||||
-rw-r--r-- | test/538-checker-embed-constants/src/Main.java | 290 |
13 files changed, 614 insertions, 153 deletions
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc index d172fba888..dd538824bd 100644 --- a/compiler/optimizing/code_generator_arm.cc +++ b/compiler/optimizing/code_generator_arm.cc @@ -3512,6 +3512,47 @@ void LocationsBuilderARM::HandleFieldGet(HInstruction* instruction, const FieldI } } +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 @@ void InstructionCodeGeneratorARM::VisitMonitorOperation(HMonitorOperation* instr 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 @@ void InstructionCodeGeneratorARM::VisitXor(HXor* instruction) { 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 16d1d383b4..6900933e87 100644 --- a/compiler/optimizing/code_generator_arm.h +++ b/compiler/optimizing/code_generator_arm.h @@ -169,11 +169,15 @@ class LocationsBuilderARM : public HGraphVisitor { 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 @@ class InstructionCodeGeneratorARM : public HGraphVisitor { // 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 967b191d32..bb771133be 100644 --- a/compiler/utils/arm/assembler_arm.h +++ b/compiler/utils/arm/assembler_arm.h @@ -470,6 +470,13 @@ class ArmAssembler : public Assembler { 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 f7772aea3d..c6af283370 100644 --- a/compiler/utils/arm/assembler_arm32.cc +++ b/compiler/utils/arm/assembler_arm32.cc @@ -130,6 +130,15 @@ void Arm32Assembler::orr(Register rd, Register rn, const ShifterOperand& so, } +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 3407369654..d346096c22 100644 --- a/compiler/utils/arm/assembler_arm32.h +++ b/compiler/utils/arm/assembler_arm32.h @@ -74,6 +74,9 @@ class Arm32Assembler FINAL : public ArmAssembler { 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 0f6c4f5a34..b8c5fd2e2b 100644 --- a/compiler/utils/arm/assembler_thumb2.cc +++ b/compiler/utils/arm/assembler_thumb2.cc @@ -410,6 +410,7 @@ bool Thumb2Assembler::ShifterOperandCanHold(Register rd ATTRIBUTE_UNUSED, 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::orr(Register rd, Register rn, const ShifterOperand& so, } +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 @@ bool Thumb2Assembler::Is32BitDataProcessing(Condition cond, 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 @@ void Thumb2Assembler::Emit32BitDataProcessing(Condition cond ATTRIBUTE_UNUSED, 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 a1a8927f44..584a387782 100644 --- a/compiler/utils/arm/assembler_thumb2.h +++ b/compiler/utils/arm/assembler_thumb2.h @@ -98,6 +98,9 @@ class Thumb2Assembler FINAL : public ArmAssembler { 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 6b4daed909..2060064423 100644 --- a/compiler/utils/arm/constants_arm.h +++ b/compiler/utils/arm/constants_arm.h @@ -148,7 +148,8 @@ enum Opcode { 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 b2a354b63c..2ae88413e7 100644 --- a/compiler/utils/assembler_thumb_test.cc +++ b/compiler/utils/assembler_thumb_test.cc @@ -238,6 +238,7 @@ TEST(Thumb2AssemblerTest, DataProcessingRegister) { __ 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 @@ TEST(Thumb2AssemblerTest, DataProcessingImmediate) { __ 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 @@ TEST(Thumb2AssemblerTest, DataProcessingModifiedImmediate) { __ 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 82ad6429bf..b79c2e46f0 100644 --- a/compiler/utils/assembler_thumb_test_expected.cc.inc +++ b/compiler/utils/assembler_thumb_test_expected.cc.inc @@ -23,109 +23,110 @@ const char* DataProcessingRegisterResults[] = { " 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 @@ const char* DataProcessingImmediateResults[] = { " 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 @@ const char* DataProcessingModifiedImmediateResults[] = { " 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 0000000000..e69de29bb2 --- /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 0000000000..5a722ecf12 --- /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 0000000000..d8618e30fb --- /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); + } +} |