diff options
author | 2016-02-02 13:49:43 +0000 | |
---|---|---|
committer | 2016-02-24 13:10:06 +0000 | |
commit | c257da7b0fb6737f65aba426add8831e45404755 (patch) | |
tree | ef5545cd8177583d88fc7acaa7b1336e18a00e6a | |
parent | d15ede2df7d157ea5480614fd18c2bf0d37a6c2a (diff) |
ARM: Implement Reverse bits and bytes intrinsic.
- IntegerReverse
- LongReverse
- IntegerReverseBytes
- LongReverseBytes
- ShortReverseBytes
Change-Id: I3ec202696b245148a0237ff6e46ac3f1a3f8402a
-rw-r--r-- | compiler/optimizing/intrinsics_arm.cc | 89 | ||||
-rw-r--r-- | compiler/utils/arm/assembler_arm.h | 3 | ||||
-rw-r--r-- | compiler/utils/arm/assembler_arm32.cc | 44 | ||||
-rw-r--r-- | compiler/utils/arm/assembler_arm32.h | 8 | ||||
-rw-r--r-- | compiler/utils/arm/assembler_arm32_test.cc | 12 | ||||
-rw-r--r-- | compiler/utils/arm/assembler_thumb2.cc | 77 | ||||
-rw-r--r-- | compiler/utils/arm/assembler_thumb2.h | 14 | ||||
-rw-r--r-- | compiler/utils/arm/assembler_thumb2_test.cc | 24 |
8 files changed, 256 insertions, 15 deletions
diff --git a/compiler/optimizing/intrinsics_arm.cc b/compiler/optimizing/intrinsics_arm.cc index ea8669fa18..8cbdcbbcaf 100644 --- a/compiler/optimizing/intrinsics_arm.cc +++ b/compiler/optimizing/intrinsics_arm.cc @@ -1825,6 +1825,90 @@ void IntrinsicCodeGeneratorARM::VisitMathNextAfter(HInvoke* invoke) { GenFPFPToFPCall(invoke, GetAssembler(), codegen_, kQuickNextAfter); } +void IntrinsicLocationsBuilderARM::VisitIntegerReverse(HInvoke* invoke) { + CreateIntToIntLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorARM::VisitIntegerReverse(HInvoke* invoke) { + ArmAssembler* assembler = GetAssembler(); + LocationSummary* locations = invoke->GetLocations(); + + Register out = locations->Out().AsRegister<Register>(); + Register in = locations->InAt(0).AsRegister<Register>(); + + __ rbit(out, in); +} + +void IntrinsicLocationsBuilderARM::VisitLongReverse(HInvoke* invoke) { + LocationSummary* locations = new (arena_) LocationSummary(invoke, + LocationSummary::kNoCall, + kIntrinsified); + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap); +} + +void IntrinsicCodeGeneratorARM::VisitLongReverse(HInvoke* invoke) { + ArmAssembler* assembler = GetAssembler(); + LocationSummary* locations = invoke->GetLocations(); + + Register in_reg_lo = locations->InAt(0).AsRegisterPairLow<Register>(); + Register in_reg_hi = locations->InAt(0).AsRegisterPairHigh<Register>(); + Register out_reg_lo = locations->Out().AsRegisterPairLow<Register>(); + Register out_reg_hi = locations->Out().AsRegisterPairHigh<Register>(); + + __ rbit(out_reg_lo, in_reg_hi); + __ rbit(out_reg_hi, in_reg_lo); +} + +void IntrinsicLocationsBuilderARM::VisitIntegerReverseBytes(HInvoke* invoke) { + CreateIntToIntLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorARM::VisitIntegerReverseBytes(HInvoke* invoke) { + ArmAssembler* assembler = GetAssembler(); + LocationSummary* locations = invoke->GetLocations(); + + Register out = locations->Out().AsRegister<Register>(); + Register in = locations->InAt(0).AsRegister<Register>(); + + __ rev(out, in); +} + +void IntrinsicLocationsBuilderARM::VisitLongReverseBytes(HInvoke* invoke) { + LocationSummary* locations = new (arena_) LocationSummary(invoke, + LocationSummary::kNoCall, + kIntrinsified); + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap); +} + +void IntrinsicCodeGeneratorARM::VisitLongReverseBytes(HInvoke* invoke) { + ArmAssembler* assembler = GetAssembler(); + LocationSummary* locations = invoke->GetLocations(); + + Register in_reg_lo = locations->InAt(0).AsRegisterPairLow<Register>(); + Register in_reg_hi = locations->InAt(0).AsRegisterPairHigh<Register>(); + Register out_reg_lo = locations->Out().AsRegisterPairLow<Register>(); + Register out_reg_hi = locations->Out().AsRegisterPairHigh<Register>(); + + __ rev(out_reg_lo, in_reg_hi); + __ rev(out_reg_hi, in_reg_lo); +} + +void IntrinsicLocationsBuilderARM::VisitShortReverseBytes(HInvoke* invoke) { + CreateIntToIntLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorARM::VisitShortReverseBytes(HInvoke* invoke) { + ArmAssembler* assembler = GetAssembler(); + LocationSummary* locations = invoke->GetLocations(); + + Register out = locations->Out().AsRegister<Register>(); + Register in = locations->InAt(0).AsRegister<Register>(); + + __ revsh(out, in); +} + // Unimplemented intrinsics. #define UNIMPLEMENTED_INTRINSIC(Name) \ @@ -1834,12 +1918,7 @@ void IntrinsicCodeGeneratorARM::Visit ## Name(HInvoke* invoke ATTRIBUTE_UNUSED) } UNIMPLEMENTED_INTRINSIC(IntegerBitCount) -UNIMPLEMENTED_INTRINSIC(IntegerReverse) -UNIMPLEMENTED_INTRINSIC(IntegerReverseBytes) UNIMPLEMENTED_INTRINSIC(LongBitCount) -UNIMPLEMENTED_INTRINSIC(LongReverse) -UNIMPLEMENTED_INTRINSIC(LongReverseBytes) -UNIMPLEMENTED_INTRINSIC(ShortReverseBytes) UNIMPLEMENTED_INTRINSIC(MathMinDoubleDouble) UNIMPLEMENTED_INTRINSIC(MathMinFloatFloat) UNIMPLEMENTED_INTRINSIC(MathMaxDoubleDouble) diff --git a/compiler/utils/arm/assembler_arm.h b/compiler/utils/arm/assembler_arm.h index f96376d9fe..a894565425 100644 --- a/compiler/utils/arm/assembler_arm.h +++ b/compiler/utils/arm/assembler_arm.h @@ -545,6 +545,9 @@ class ArmAssembler : public Assembler { virtual void movw(Register rd, uint16_t imm16, Condition cond = AL) = 0; virtual void movt(Register rd, uint16_t imm16, Condition cond = AL) = 0; virtual void rbit(Register rd, Register rm, Condition cond = AL) = 0; + virtual void rev(Register rd, Register rm, Condition cond = AL) = 0; + virtual void rev16(Register rd, Register rm, Condition cond = AL) = 0; + virtual void revsh(Register rd, Register rm, Condition cond = AL) = 0; // Multiply instructions. virtual void mul(Register rd, Register rn, Register rm, Condition cond = AL) = 0; diff --git a/compiler/utils/arm/assembler_arm32.cc b/compiler/utils/arm/assembler_arm32.cc index ebca25bbf9..0a227b21cd 100644 --- a/compiler/utils/arm/assembler_arm32.cc +++ b/compiler/utils/arm/assembler_arm32.cc @@ -750,6 +750,35 @@ void Arm32Assembler::movt(Register rd, uint16_t imm16, Condition cond) { } +void Arm32Assembler::EmitMiscellaneous(Condition cond, uint8_t op1, + uint8_t op2, uint32_t a_part, + uint32_t rest) { + int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | + B26 | B25 | B23 | + (op1 << 20) | + (a_part << 16) | + (op2 << 5) | + B4 | + rest; + Emit(encoding); +} + + +void Arm32Assembler::EmitReverseBytes(Register rd, Register rm, Condition cond, + uint8_t op1, uint8_t op2) { + CHECK_NE(rd, kNoRegister); + CHECK_NE(rm, kNoRegister); + CHECK_NE(cond, kNoCondition); + CHECK_NE(rd, PC); + CHECK_NE(rm, PC); + + int32_t encoding = (static_cast<int32_t>(rd) << kRdShift) | + (0b1111 << 8) | + static_cast<int32_t>(rm); + EmitMiscellaneous(cond, op1, op2, 0b1111, encoding); +} + + void Arm32Assembler::rbit(Register rd, Register rm, Condition cond) { CHECK_NE(rd, kNoRegister); CHECK_NE(rm, kNoRegister); @@ -764,6 +793,21 @@ void Arm32Assembler::rbit(Register rd, Register rm, Condition cond) { } +void Arm32Assembler::rev(Register rd, Register rm, Condition cond) { + EmitReverseBytes(rd, rm, cond, 0b011, 0b001); +} + + +void Arm32Assembler::rev16(Register rd, Register rm, Condition cond) { + EmitReverseBytes(rd, rm, cond, 0b011, 0b101); +} + + +void Arm32Assembler::revsh(Register rd, Register rm, Condition cond) { + EmitReverseBytes(rd, rm, cond, 0b111, 0b101); +} + + void Arm32Assembler::EmitMulOp(Condition cond, int32_t opcode, Register rd, Register rn, Register rm, Register rs) { diff --git a/compiler/utils/arm/assembler_arm32.h b/compiler/utils/arm/assembler_arm32.h index bf332feb62..e3e05caf92 100644 --- a/compiler/utils/arm/assembler_arm32.h +++ b/compiler/utils/arm/assembler_arm32.h @@ -91,6 +91,9 @@ class Arm32Assembler FINAL : public ArmAssembler { void movw(Register rd, uint16_t imm16, Condition cond = AL) OVERRIDE; void movt(Register rd, uint16_t imm16, Condition cond = AL) OVERRIDE; void rbit(Register rd, Register rm, Condition cond = AL) OVERRIDE; + void rev(Register rd, Register rm, Condition cond = AL) OVERRIDE; + void rev16(Register rd, Register rm, Condition cond = AL) OVERRIDE; + void revsh(Register rd, Register rm, Condition cond = AL) OVERRIDE; // Multiply instructions. void mul(Register rd, Register rn, Register rm, Condition cond = AL) OVERRIDE; @@ -388,6 +391,11 @@ class Arm32Assembler FINAL : public ArmAssembler { void EmitVPushPop(uint32_t reg, int nregs, bool push, bool dbl, Condition cond); + void EmitMiscellaneous(Condition cond, uint8_t op1, uint8_t op2, + uint32_t a_part, uint32_t rest); + void EmitReverseBytes(Register rd, Register rm, Condition cond, + uint8_t op1, uint8_t op2); + void EmitBranch(Condition cond, Label* label, bool link); static int32_t EncodeBranchOffset(int offset, int32_t inst); static int DecodeBranchOffset(int32_t inst); diff --git a/compiler/utils/arm/assembler_arm32_test.cc b/compiler/utils/arm/assembler_arm32_test.cc index 43805966a9..e570e22fca 100644 --- a/compiler/utils/arm/assembler_arm32_test.cc +++ b/compiler/utils/arm/assembler_arm32_test.cc @@ -887,4 +887,16 @@ TEST_F(AssemblerArm32Test, rbit) { T3Helper(&arm::Arm32Assembler::rbit, true, "rbit{cond} {reg1}, {reg2}", "rbit"); } +TEST_F(AssemblerArm32Test, rev) { + T3Helper(&arm::Arm32Assembler::rev, true, "rev{cond} {reg1}, {reg2}", "rev"); +} + +TEST_F(AssemblerArm32Test, rev16) { + T3Helper(&arm::Arm32Assembler::rev16, true, "rev16{cond} {reg1}, {reg2}", "rev16"); +} + +TEST_F(AssemblerArm32Test, revsh) { + T3Helper(&arm::Arm32Assembler::revsh, true, "revsh{cond} {reg1}, {reg2}", "revsh"); +} + } // namespace art diff --git a/compiler/utils/arm/assembler_thumb2.cc b/compiler/utils/arm/assembler_thumb2.cc index 52023a67ee..15298b390b 100644 --- a/compiler/utils/arm/assembler_thumb2.cc +++ b/compiler/utils/arm/assembler_thumb2.cc @@ -2569,20 +2569,36 @@ void Thumb2Assembler::EmitBranch(Condition cond, Label* label, bool link, bool x } +void Thumb2Assembler::Emit32Miscellaneous(uint8_t op1, + uint8_t op2, + uint32_t rest_encoding) { + int32_t encoding = B31 | B30 | B29 | B28 | B27 | B25 | B23 | + op1 << 20 | + 0xf << 12 | + B7 | + op2 << 4 | + rest_encoding; + Emit32(encoding); +} + + +void Thumb2Assembler::Emit16Miscellaneous(uint32_t rest_encoding) { + int16_t encoding = B15 | B13 | B12 | + rest_encoding; + Emit16(encoding); +} + void Thumb2Assembler::clz(Register rd, Register rm, Condition cond) { CHECK_NE(rd, kNoRegister); CHECK_NE(rm, kNoRegister); CheckCondition(cond); CHECK_NE(rd, PC); CHECK_NE(rm, PC); - int32_t encoding = B31 | B30 | B29 | B28 | B27 | - B25 | B23 | B21 | B20 | + int32_t encoding = static_cast<uint32_t>(rm) << 16 | - 0xf << 12 | static_cast<uint32_t>(rd) << 8 | - B7 | static_cast<uint32_t>(rm); - Emit32(encoding); + Emit32Miscellaneous(0b11, 0b00, encoding); } @@ -2630,14 +2646,55 @@ void Thumb2Assembler::rbit(Register rd, Register rm, Condition cond) { CHECK_NE(rm, PC); CHECK_NE(rd, SP); CHECK_NE(rm, SP); - int32_t encoding = B31 | B30 | B29 | B28 | B27 | - B25 | B23 | B20 | + int32_t encoding = static_cast<uint32_t>(rm) << 16 | - 0xf << 12 | static_cast<uint32_t>(rd) << 8 | - B7 | B5 | static_cast<uint32_t>(rm); - Emit32(encoding); + + Emit32Miscellaneous(0b01, 0b10, encoding); +} + + +void Thumb2Assembler::EmitReverseBytes(Register rd, Register rm, + uint32_t op) { + CHECK_NE(rd, kNoRegister); + CHECK_NE(rm, kNoRegister); + CHECK_NE(rd, PC); + CHECK_NE(rm, PC); + CHECK_NE(rd, SP); + CHECK_NE(rm, SP); + + if (!IsHighRegister(rd) && !IsHighRegister(rm) && !force_32bit_) { + uint16_t t1_op = B11 | B9 | (op << 6); + int16_t encoding = t1_op | + static_cast<uint16_t>(rm) << 3 | + static_cast<uint16_t>(rd); + Emit16Miscellaneous(encoding); + } else { + int32_t encoding = + static_cast<uint32_t>(rm) << 16 | + static_cast<uint32_t>(rd) << 8 | + static_cast<uint32_t>(rm); + Emit32Miscellaneous(0b01, op, encoding); + } +} + + +void Thumb2Assembler::rev(Register rd, Register rm, Condition cond) { + CheckCondition(cond); + EmitReverseBytes(rd, rm, 0b00); +} + + +void Thumb2Assembler::rev16(Register rd, Register rm, Condition cond) { + CheckCondition(cond); + EmitReverseBytes(rd, rm, 0b01); +} + + +void Thumb2Assembler::revsh(Register rd, Register rm, Condition cond) { + CheckCondition(cond); + EmitReverseBytes(rd, rm, 0b11); } diff --git a/compiler/utils/arm/assembler_thumb2.h b/compiler/utils/arm/assembler_thumb2.h index bf07b2dbf8..6b61acafac 100644 --- a/compiler/utils/arm/assembler_thumb2.h +++ b/compiler/utils/arm/assembler_thumb2.h @@ -117,6 +117,9 @@ class Thumb2Assembler FINAL : public ArmAssembler { void movw(Register rd, uint16_t imm16, Condition cond = AL) OVERRIDE; void movt(Register rd, uint16_t imm16, Condition cond = AL) OVERRIDE; void rbit(Register rd, Register rm, Condition cond = AL) OVERRIDE; + void rev(Register rd, Register rm, Condition cond = AL) OVERRIDE; + void rev16(Register rd, Register rm, Condition cond = AL) OVERRIDE; + void revsh(Register rd, Register rm, Condition cond = AL) OVERRIDE; // Multiply instructions. void mul(Register rd, Register rn, Register rm, Condition cond = AL) OVERRIDE; @@ -644,6 +647,17 @@ class Thumb2Assembler FINAL : public ArmAssembler { Register rd, const ShifterOperand& so); + // Emit a single 32 bit miscellaneous instruction. + void Emit32Miscellaneous(uint8_t op1, + uint8_t op2, + uint32_t rest_encoding); + + // Emit reverse byte instructions: rev, rev16, revsh. + void EmitReverseBytes(Register rd, Register rm, uint32_t op); + + // Emit a single 16 bit miscellaneous instruction. + void Emit16Miscellaneous(uint32_t rest_encoding); + // Must the instruction be 32 bits or can it possibly be encoded // in 16 bits? bool Is32BitDataProcessing(Condition cond, diff --git a/compiler/utils/arm/assembler_thumb2_test.cc b/compiler/utils/arm/assembler_thumb2_test.cc index 7b32b0fd26..650b08900b 100644 --- a/compiler/utils/arm/assembler_thumb2_test.cc +++ b/compiler/utils/arm/assembler_thumb2_test.cc @@ -1331,4 +1331,28 @@ TEST_F(AssemblerThumb2Test, rbit) { DriverStr(expected, "rbit"); } +TEST_F(AssemblerThumb2Test, rev) { + __ rev(arm::R1, arm::R0); + + const char* expected = "rev r1, r0\n"; + + DriverStr(expected, "rev"); +} + +TEST_F(AssemblerThumb2Test, rev16) { + __ rev16(arm::R1, arm::R0); + + const char* expected = "rev16 r1, r0\n"; + + DriverStr(expected, "rev16"); +} + +TEST_F(AssemblerThumb2Test, revsh) { + __ revsh(arm::R1, arm::R0); + + const char* expected = "revsh r1, r0\n"; + + DriverStr(expected, "revsh"); +} + } // namespace art |