diff options
| author | 2015-07-23 10:44:35 +0100 | |
|---|---|---|
| committer | 2015-09-11 09:51:58 +0100 | |
| commit | 9ee23f4273efed8d6378f6ad8e63c65e30a17139 (patch) | |
| tree | 3b1bfb8a6260a57ccb2f025fcdc457464714701e /compiler | |
| parent | 62ba40149be3d1c65e4db1f455822a585149d32f (diff) | |
ARM/ARM64: Intrinsics - numberOfTrailingZeros, rotateLeft, rotateRight
Change-Id: I2a07c279756ee804fb7c129416bdc4a3962e93ed
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/dex/quick/dex_file_method_inliner.cc | 24 | ||||
| -rw-r--r-- | compiler/dex/quick/dex_file_method_inliner.h | 4 | ||||
| -rw-r--r-- | compiler/optimizing/intrinsics.cc | 32 | ||||
| -rw-r--r-- | compiler/optimizing/intrinsics_arm.cc | 221 | ||||
| -rw-r--r-- | compiler/optimizing/intrinsics_arm64.cc | 127 | ||||
| -rw-r--r-- | compiler/optimizing/intrinsics_list.h | 6 | ||||
| -rw-r--r-- | compiler/optimizing/intrinsics_x86.cc | 6 | ||||
| -rw-r--r-- | compiler/optimizing/intrinsics_x86_64.cc | 6 | ||||
| -rw-r--r-- | compiler/utils/arm/assembler_arm.h | 1 | ||||
| -rw-r--r-- | compiler/utils/arm/assembler_arm32.cc | 14 | ||||
| -rw-r--r-- | compiler/utils/arm/assembler_arm32.h | 1 | ||||
| -rw-r--r-- | compiler/utils/arm/assembler_arm32_test.cc | 4 | ||||
| -rw-r--r-- | compiler/utils/arm/assembler_thumb2.cc | 19 | ||||
| -rw-r--r-- | compiler/utils/arm/assembler_thumb2.h | 1 | ||||
| -rw-r--r-- | compiler/utils/arm/assembler_thumb2_test.cc | 8 |
15 files changed, 472 insertions, 2 deletions
diff --git a/compiler/dex/quick/dex_file_method_inliner.cc b/compiler/dex/quick/dex_file_method_inliner.cc index 42b792ca1a..af93aabc91 100644 --- a/compiler/dex/quick/dex_file_method_inliner.cc +++ b/compiler/dex/quick/dex_file_method_inliner.cc @@ -39,6 +39,9 @@ static constexpr bool kIntrinsicIsStatic[] = { true, // kIntrinsicReverseBits true, // kIntrinsicReverseBytes true, // kIntrinsicNumberOfLeadingZeros + true, // kIntrinsicNumberOfTrailingZeros + true, // kIntrinsicRotateRight + true, // kIntrinsicRotateLeft true, // kIntrinsicAbsInt true, // kIntrinsicAbsLong true, // kIntrinsicAbsFloat @@ -79,6 +82,10 @@ static_assert(kIntrinsicIsStatic[kIntrinsicReverseBits], "ReverseBits must be st static_assert(kIntrinsicIsStatic[kIntrinsicReverseBytes], "ReverseBytes must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicNumberOfLeadingZeros], "NumberOfLeadingZeros must be static"); +static_assert(kIntrinsicIsStatic[kIntrinsicNumberOfTrailingZeros], + "NumberOfTrailingZeros must be static"); +static_assert(kIntrinsicIsStatic[kIntrinsicRotateRight], "RotateRight must be static"); +static_assert(kIntrinsicIsStatic[kIntrinsicRotateLeft], "RotateLeft must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicAbsInt], "AbsInt must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicAbsLong], "AbsLong must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicAbsFloat], "AbsFloat must be static"); @@ -232,6 +239,9 @@ const char* const DexFileMethodInliner::kNameCacheNames[] = { "putOrderedObject", // kNameCachePutOrderedObject "arraycopy", // kNameCacheArrayCopy "numberOfLeadingZeros", // kNameCacheNumberOfLeadingZeros + "numberOfTrailingZeros", // kNameCacheNumberOfTrailingZeros + "rotateRight", // kNameCacheRotateRight + "rotateLeft", // kNameCacheRotateLeft }; const DexFileMethodInliner::ProtoDef DexFileMethodInliner::kProtoCacheDefs[] = { @@ -289,6 +299,8 @@ const DexFileMethodInliner::ProtoDef DexFileMethodInliner::kProtoCacheDefs[] = { { kClassCacheVoid, 2, { kClassCacheLong, kClassCacheShort } }, // kProtoCacheObject_Z { kClassCacheBoolean, 1, { kClassCacheJavaLangObject } }, + // kProtoCacheJI_J + { kClassCacheLong, 2, { kClassCacheLong, kClassCacheInt } }, // kProtoCacheObjectJII_Z { kClassCacheBoolean, 4, { kClassCacheJavaLangObject, kClassCacheLong, kClassCacheInt, kClassCacheInt } }, @@ -379,6 +391,8 @@ const DexFileMethodInliner::IntrinsicDef DexFileMethodInliner::kIntrinsicMethods INTRINSIC(JavaLangInteger, NumberOfLeadingZeros, I_I, kIntrinsicNumberOfLeadingZeros, k32), INTRINSIC(JavaLangLong, NumberOfLeadingZeros, J_I, kIntrinsicNumberOfLeadingZeros, k64), + INTRINSIC(JavaLangInteger, NumberOfTrailingZeros, I_I, kIntrinsicNumberOfTrailingZeros, k32), + INTRINSIC(JavaLangLong, NumberOfTrailingZeros, J_I, kIntrinsicNumberOfTrailingZeros, k64), INTRINSIC(JavaLangMath, Abs, I_I, kIntrinsicAbsInt, 0), INTRINSIC(JavaLangStrictMath, Abs, I_I, kIntrinsicAbsInt, 0), @@ -468,6 +482,11 @@ const DexFileMethodInliner::IntrinsicDef DexFileMethodInliner::kIntrinsicMethods INTRINSIC(JavaLangSystem, ArrayCopy, CharArrayICharArrayII_V , kIntrinsicSystemArrayCopyCharArray, 0), + INTRINSIC(JavaLangInteger, RotateRight, II_I, kIntrinsicRotateRight, k32), + INTRINSIC(JavaLangLong, RotateRight, JI_J, kIntrinsicRotateRight, k64), + INTRINSIC(JavaLangInteger, RotateLeft, II_I, kIntrinsicRotateLeft, k32), + INTRINSIC(JavaLangLong, RotateLeft, JI_J, kIntrinsicRotateLeft, k64), + #undef INTRINSIC #define SPECIAL(c, n, p, o, d) \ @@ -631,7 +650,10 @@ bool DexFileMethodInliner::GenIntrinsic(Mir2Lir* backend, CallInfo* info) { case kIntrinsicSystemArrayCopyCharArray: return backend->GenInlinedArrayCopyCharArray(info); case kIntrinsicNumberOfLeadingZeros: - return false; // not implemented in quick + case kIntrinsicNumberOfTrailingZeros: + case kIntrinsicRotateRight: + case kIntrinsicRotateLeft: + return false; // not implemented in quick. default: LOG(FATAL) << "Unexpected intrinsic opcode: " << intrinsic.opcode; return false; // avoid warning "control reaches end of non-void function" diff --git a/compiler/dex/quick/dex_file_method_inliner.h b/compiler/dex/quick/dex_file_method_inliner.h index d6c8bfbdb6..8458806e5e 100644 --- a/compiler/dex/quick/dex_file_method_inliner.h +++ b/compiler/dex/quick/dex_file_method_inliner.h @@ -208,6 +208,9 @@ class DexFileMethodInliner { kNameCachePutOrderedObject, kNameCacheArrayCopy, kNameCacheNumberOfLeadingZeros, + kNameCacheNumberOfTrailingZeros, + kNameCacheRotateRight, + kNameCacheRotateLeft, kNameCacheLast }; @@ -245,6 +248,7 @@ class DexFileMethodInliner { kProtoCacheJJ_V, kProtoCacheJS_V, kProtoCacheObject_Z, + kProtoCacheJI_J, kProtoCacheObjectJII_Z, kProtoCacheObjectJJJ_Z, kProtoCacheObjectJObjectObject_Z, diff --git a/compiler/optimizing/intrinsics.cc b/compiler/optimizing/intrinsics.cc index 075ec1ee2e..2dd4bbabdb 100644 --- a/compiler/optimizing/intrinsics.cc +++ b/compiler/optimizing/intrinsics.cc @@ -120,6 +120,28 @@ static Intrinsics GetIntrinsic(InlineMethod method, InstructionSet instruction_s LOG(FATAL) << "Unknown/unsupported op size " << method.d.data; UNREACHABLE(); } + case kIntrinsicRotateRight: + switch (GetType(method.d.data, true)) { + case Primitive::kPrimInt: + return Intrinsics::kIntegerRotateRight; + case Primitive::kPrimLong: + return Intrinsics::kLongRotateRight; + default: + LOG(FATAL) << "Unknown/unsupported op size " << method.d.data; + UNREACHABLE(); + } + case kIntrinsicRotateLeft: + switch (GetType(method.d.data, true)) { + case Primitive::kPrimInt: + return Intrinsics::kIntegerRotateLeft; + case Primitive::kPrimLong: + return Intrinsics::kLongRotateLeft; + default: + LOG(FATAL) << "Unknown/unsupported op size " << method.d.data; + UNREACHABLE(); + } + + // Misc data processing. case kIntrinsicNumberOfLeadingZeros: switch (GetType(method.d.data, true)) { case Primitive::kPrimInt: @@ -130,6 +152,16 @@ static Intrinsics GetIntrinsic(InlineMethod method, InstructionSet instruction_s LOG(FATAL) << "Unknown/unsupported op size " << method.d.data; UNREACHABLE(); } + case kIntrinsicNumberOfTrailingZeros: + switch (GetType(method.d.data, true)) { + case Primitive::kPrimInt: + return Intrinsics::kIntegerNumberOfTrailingZeros; + case Primitive::kPrimLong: + return Intrinsics::kLongNumberOfTrailingZeros; + default: + LOG(FATAL) << "Unknown/unsupported op size " << method.d.data; + UNREACHABLE(); + } // Abs. case kIntrinsicAbsDouble: diff --git a/compiler/optimizing/intrinsics_arm.cc b/compiler/optimizing/intrinsics_arm.cc index 69a3e627c9..b7dc1df1db 100644 --- a/compiler/optimizing/intrinsics_arm.cc +++ b/compiler/optimizing/intrinsics_arm.cc @@ -266,6 +266,227 @@ void IntrinsicCodeGeneratorARM::VisitLongNumberOfLeadingZeros(HInvoke* invoke) { GenNumberOfLeadingZeros(invoke->GetLocations(), Primitive::kPrimLong, GetAssembler()); } +static void GenNumberOfTrailingZeros(LocationSummary* locations, + Primitive::Type type, + ArmAssembler* assembler) { + DCHECK((type == Primitive::kPrimInt) || (type == Primitive::kPrimLong)); + + Register out = locations->Out().AsRegister<Register>(); + + if (type == Primitive::kPrimLong) { + Register in_reg_lo = locations->InAt(0).AsRegisterPairLow<Register>(); + Register in_reg_hi = locations->InAt(0).AsRegisterPairHigh<Register>(); + Label end; + __ rbit(out, in_reg_lo); + __ clz(out, out); + __ CompareAndBranchIfNonZero(in_reg_lo, &end); + __ rbit(out, in_reg_hi); + __ clz(out, out); + __ AddConstant(out, 32); + __ Bind(&end); + } else { + Register in = locations->InAt(0).AsRegister<Register>(); + __ rbit(out, in); + __ clz(out, out); + } +} + +void IntrinsicLocationsBuilderARM::VisitIntegerNumberOfTrailingZeros(HInvoke* invoke) { + LocationSummary* locations = new (arena_) LocationSummary(invoke, + LocationSummary::kNoCall, + kIntrinsified); + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); +} + +void IntrinsicCodeGeneratorARM::VisitIntegerNumberOfTrailingZeros(HInvoke* invoke) { + GenNumberOfTrailingZeros(invoke->GetLocations(), Primitive::kPrimInt, GetAssembler()); +} + +void IntrinsicLocationsBuilderARM::VisitLongNumberOfTrailingZeros(HInvoke* invoke) { + LocationSummary* locations = new (arena_) LocationSummary(invoke, + LocationSummary::kNoCall, + kIntrinsified); + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap); +} + +void IntrinsicCodeGeneratorARM::VisitLongNumberOfTrailingZeros(HInvoke* invoke) { + GenNumberOfTrailingZeros(invoke->GetLocations(), Primitive::kPrimLong, GetAssembler()); +} + +static void GenIntegerRotate(LocationSummary* locations, + ArmAssembler* assembler, + bool is_left) { + Register in = locations->InAt(0).AsRegister<Register>(); + Location rhs = locations->InAt(1); + Register out = locations->Out().AsRegister<Register>(); + + if (rhs.IsConstant()) { + // Arm32 and Thumb2 assemblers require a rotation on the interval [1,31], + // so map all rotations to a +ve. equivalent in that range. + // (e.g. left *or* right by -2 bits == 30 bits in the same direction.) + uint32_t rot = rhs.GetConstant()->AsIntConstant()->GetValue() & 0x1F; + if (rot) { + // Rotate, mapping left rotations to right equivalents if necessary. + // (e.g. left by 2 bits == right by 30.) + __ Ror(out, in, is_left ? (0x20 - rot) : rot); + } else if (out != in) { + __ Mov(out, in); + } + } else { + if (is_left) { + __ rsb(out, rhs.AsRegister<Register>(), ShifterOperand(0)); + __ Ror(out, in, out); + } else { + __ Ror(out, in, rhs.AsRegister<Register>()); + } + } +} + +// Gain some speed by mapping all Long rotates onto equivalent pairs of Integer +// rotates by swapping input regs (effectively rotating by the first 32-bits of +// a larger rotation) or flipping direction (thus treating larger right/left +// rotations as sub-word sized rotations in the other direction) as appropriate. +static void GenLongRotate(LocationSummary* locations, + ArmAssembler* assembler, + bool is_left) { + Register in_reg_lo = locations->InAt(0).AsRegisterPairLow<Register>(); + Register in_reg_hi = locations->InAt(0).AsRegisterPairHigh<Register>(); + Location rhs = locations->InAt(1); + Register out_reg_lo = locations->Out().AsRegisterPairLow<Register>(); + Register out_reg_hi = locations->Out().AsRegisterPairHigh<Register>(); + + if (rhs.IsConstant()) { + uint32_t rot = rhs.GetConstant()->AsIntConstant()->GetValue(); + // Map all left rotations to right equivalents. + if (is_left) { + rot = 0x40 - rot; + } + // Map all rotations to +ve. equivalents on the interval [0,63]. + rot &= 0x3F; + // For rotates over a word in size, 'pre-rotate' by 32-bits to keep rotate + // logic below to a simple pair of binary orr. + // (e.g. 34 bits == in_reg swap + 2 bits right.) + if (rot >= 0x20) { + rot -= 0x20; + std::swap(in_reg_hi, in_reg_lo); + } + // Rotate, or mov to out for zero or word size rotations. + if (rot) { + __ Lsr(out_reg_hi, in_reg_hi, rot); + __ orr(out_reg_hi, out_reg_hi, ShifterOperand(in_reg_lo, arm::LSL, 0x20 - rot)); + __ Lsr(out_reg_lo, in_reg_lo, rot); + __ orr(out_reg_lo, out_reg_lo, ShifterOperand(in_reg_hi, arm::LSL, 0x20 - rot)); + } else { + __ Mov(out_reg_lo, in_reg_lo); + __ Mov(out_reg_hi, in_reg_hi); + } + } else { + Register shift_left = locations->GetTemp(0).AsRegister<Register>(); + Register shift_right = locations->GetTemp(1).AsRegister<Register>(); + Label end; + Label right; + + __ and_(shift_left, rhs.AsRegister<Register>(), ShifterOperand(0x1F)); + __ Lsrs(shift_right, rhs.AsRegister<Register>(), 6); + __ rsb(shift_right, shift_left, ShifterOperand(0x20), AL, kCcKeep); + + if (is_left) { + __ b(&right, CS); + } else { + __ b(&right, CC); + std::swap(shift_left, shift_right); + } + + // out_reg_hi = (reg_hi << shift_left) | (reg_lo >> shift_right). + // out_reg_lo = (reg_lo << shift_left) | (reg_hi >> shift_right). + __ Lsl(out_reg_hi, in_reg_hi, shift_left); + __ Lsr(out_reg_lo, in_reg_lo, shift_right); + __ add(out_reg_hi, out_reg_hi, ShifterOperand(out_reg_lo)); + __ Lsl(out_reg_lo, in_reg_lo, shift_left); + __ Lsr(shift_left, in_reg_hi, shift_right); + __ add(out_reg_lo, out_reg_lo, ShifterOperand(shift_left)); + __ b(&end); + + // out_reg_hi = (reg_hi >> shift_right) | (reg_lo << shift_left). + // out_reg_lo = (reg_lo >> shift_right) | (reg_hi << shift_left). + __ Bind(&right); + __ Lsr(out_reg_hi, in_reg_hi, shift_right); + __ Lsl(out_reg_lo, in_reg_lo, shift_left); + __ add(out_reg_hi, out_reg_hi, ShifterOperand(out_reg_lo)); + __ Lsr(out_reg_lo, in_reg_lo, shift_right); + __ Lsl(shift_right, in_reg_hi, shift_left); + __ add(out_reg_lo, out_reg_lo, ShifterOperand(shift_right)); + + __ Bind(&end); + } +} + +void IntrinsicLocationsBuilderARM::VisitIntegerRotateRight(HInvoke* invoke) { + LocationSummary* locations = new (arena_) LocationSummary(invoke, + LocationSummary::kNoCall, + kIntrinsified); + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::RegisterOrConstant(invoke->InputAt(1))); + locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); +} + +void IntrinsicCodeGeneratorARM::VisitIntegerRotateRight(HInvoke* invoke) { + GenIntegerRotate(invoke->GetLocations(), GetAssembler(), false /* is_left */); +} + +void IntrinsicLocationsBuilderARM::VisitLongRotateRight(HInvoke* invoke) { + LocationSummary* locations = new (arena_) LocationSummary(invoke, + LocationSummary::kNoCall, + kIntrinsified); + locations->SetInAt(0, Location::RequiresRegister()); + if (invoke->InputAt(1)->IsConstant()) { + locations->SetInAt(1, Location::ConstantLocation(invoke->InputAt(1)->AsConstant())); + } else { + locations->SetInAt(1, Location::RequiresRegister()); + locations->AddTemp(Location::RequiresRegister()); + locations->AddTemp(Location::RequiresRegister()); + } + locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap); +} + +void IntrinsicCodeGeneratorARM::VisitLongRotateRight(HInvoke* invoke) { + GenLongRotate(invoke->GetLocations(), GetAssembler(), false /* is_left */); +} + +void IntrinsicLocationsBuilderARM::VisitIntegerRotateLeft(HInvoke* invoke) { + LocationSummary* locations = new (arena_) LocationSummary(invoke, + LocationSummary::kNoCall, + kIntrinsified); + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::RegisterOrConstant(invoke->InputAt(1))); + locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap); +} + +void IntrinsicCodeGeneratorARM::VisitIntegerRotateLeft(HInvoke* invoke) { + GenIntegerRotate(invoke->GetLocations(), GetAssembler(), true /* is_left */); +} + +void IntrinsicLocationsBuilderARM::VisitLongRotateLeft(HInvoke* invoke) { + LocationSummary* locations = new (arena_) LocationSummary(invoke, + LocationSummary::kNoCall, + kIntrinsified); + locations->SetInAt(0, Location::RequiresRegister()); + if (invoke->InputAt(1)->IsConstant()) { + locations->SetInAt(1, Location::ConstantLocation(invoke->InputAt(1)->AsConstant())); + } else { + locations->SetInAt(1, Location::RequiresRegister()); + locations->AddTemp(Location::RequiresRegister()); + locations->AddTemp(Location::RequiresRegister()); + } + locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap); +} + +void IntrinsicCodeGeneratorARM::VisitLongRotateLeft(HInvoke* invoke) { + GenLongRotate(invoke->GetLocations(), GetAssembler(), true /* is_left */); +} + static void MathAbsFP(LocationSummary* locations, bool is64bit, ArmAssembler* assembler) { Location in = locations->InAt(0); Location out = locations->Out(); diff --git a/compiler/optimizing/intrinsics_arm64.cc b/compiler/optimizing/intrinsics_arm64.cc index 0171d6949d..5efa01e1da 100644 --- a/compiler/optimizing/intrinsics_arm64.cc +++ b/compiler/optimizing/intrinsics_arm64.cc @@ -41,12 +41,12 @@ using helpers::DRegisterFrom; using helpers::FPRegisterFrom; using helpers::HeapOperand; using helpers::LocationFrom; +using helpers::OperandFrom; using helpers::RegisterFrom; using helpers::SRegisterFrom; using helpers::WRegisterFrom; using helpers::XRegisterFrom; - namespace { ALWAYS_INLINE inline MemOperand AbsoluteHeapOperandFrom(Location location, size_t offset = 0) { @@ -287,6 +287,131 @@ void IntrinsicCodeGeneratorARM64::VisitLongNumberOfLeadingZeros(HInvoke* invoke) GenNumberOfLeadingZeros(invoke->GetLocations(), Primitive::kPrimLong, GetVIXLAssembler()); } +static void GenNumberOfTrailingZeros(LocationSummary* locations, + Primitive::Type type, + vixl::MacroAssembler* masm) { + DCHECK(type == Primitive::kPrimInt || type == Primitive::kPrimLong); + + Location in = locations->InAt(0); + Location out = locations->Out(); + + __ Rbit(RegisterFrom(out, type), RegisterFrom(in, type)); + __ Clz(RegisterFrom(out, type), RegisterFrom(out, type)); +} + +void IntrinsicLocationsBuilderARM64::VisitIntegerNumberOfTrailingZeros(HInvoke* invoke) { + CreateIntToIntLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorARM64::VisitIntegerNumberOfTrailingZeros(HInvoke* invoke) { + GenNumberOfTrailingZeros(invoke->GetLocations(), Primitive::kPrimInt, GetVIXLAssembler()); +} + +void IntrinsicLocationsBuilderARM64::VisitLongNumberOfTrailingZeros(HInvoke* invoke) { + CreateIntToIntLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorARM64::VisitLongNumberOfTrailingZeros(HInvoke* invoke) { + GenNumberOfTrailingZeros(invoke->GetLocations(), Primitive::kPrimLong, GetVIXLAssembler()); +} + +static void GenRotateRight(LocationSummary* locations, + Primitive::Type type, + vixl::MacroAssembler* masm) { + DCHECK(type == Primitive::kPrimInt || type == Primitive::kPrimLong); + + Location in = locations->InAt(0); + Location out = locations->Out(); + Operand rhs = OperandFrom(locations->InAt(1), type); + + if (rhs.IsImmediate()) { + uint32_t shift = rhs.immediate() & (RegisterFrom(in, type).SizeInBits() - 1); + __ Ror(RegisterFrom(out, type), + RegisterFrom(in, type), + shift); + } else { + DCHECK(rhs.shift() == vixl::LSL && rhs.shift_amount() == 0); + __ Ror(RegisterFrom(out, type), + RegisterFrom(in, type), + rhs.reg()); + } +} + +void IntrinsicLocationsBuilderARM64::VisitIntegerRotateRight(HInvoke* invoke) { + LocationSummary* locations = new (arena_) LocationSummary(invoke, + LocationSummary::kNoCall, + kIntrinsified); + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::RegisterOrConstant(invoke->InputAt(1))); + locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); +} + +void IntrinsicCodeGeneratorARM64::VisitIntegerRotateRight(HInvoke* invoke) { + GenRotateRight(invoke->GetLocations(), Primitive::kPrimInt, GetVIXLAssembler()); +} + +void IntrinsicLocationsBuilderARM64::VisitLongRotateRight(HInvoke* invoke) { + LocationSummary* locations = new (arena_) LocationSummary(invoke, + LocationSummary::kNoCall, + kIntrinsified); + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::RegisterOrConstant(invoke->InputAt(1))); + locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); +} + +void IntrinsicCodeGeneratorARM64::VisitLongRotateRight(HInvoke* invoke) { + GenRotateRight(invoke->GetLocations(), Primitive::kPrimLong, GetVIXLAssembler()); +} + +static void GenRotateLeft(LocationSummary* locations, + Primitive::Type type, + vixl::MacroAssembler* masm) { + DCHECK(type == Primitive::kPrimInt || type == Primitive::kPrimLong); + + Location in = locations->InAt(0); + Location out = locations->Out(); + Operand rhs = OperandFrom(locations->InAt(1), type); + + if (rhs.IsImmediate()) { + uint32_t regsize = RegisterFrom(in, type).SizeInBits(); + uint32_t shift = (regsize - rhs.immediate()) & (regsize - 1); + __ Ror(RegisterFrom(out, type), RegisterFrom(in, type), shift); + } else { + DCHECK(rhs.shift() == vixl::LSL && rhs.shift_amount() == 0); + __ Neg(RegisterFrom(out, type), + Operand(RegisterFrom(locations->InAt(1), type))); + __ Ror(RegisterFrom(out, type), + RegisterFrom(in, type), + RegisterFrom(out, type)); + } +} + +void IntrinsicLocationsBuilderARM64::VisitIntegerRotateLeft(HInvoke* invoke) { + LocationSummary* locations = new (arena_) LocationSummary(invoke, + LocationSummary::kNoCall, + kIntrinsified); + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::RegisterOrConstant(invoke->InputAt(1))); + locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap); +} + +void IntrinsicCodeGeneratorARM64::VisitIntegerRotateLeft(HInvoke* invoke) { + GenRotateLeft(invoke->GetLocations(), Primitive::kPrimInt, GetVIXLAssembler()); +} + +void IntrinsicLocationsBuilderARM64::VisitLongRotateLeft(HInvoke* invoke) { + LocationSummary* locations = new (arena_) LocationSummary(invoke, + LocationSummary::kNoCall, + kIntrinsified); + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::RegisterOrConstant(invoke->InputAt(1))); + locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap); +} + +void IntrinsicCodeGeneratorARM64::VisitLongRotateLeft(HInvoke* invoke) { + GenRotateLeft(invoke->GetLocations(), Primitive::kPrimLong, GetVIXLAssembler()); +} + static void GenReverse(LocationSummary* locations, Primitive::Type type, vixl::MacroAssembler* masm) { diff --git a/compiler/optimizing/intrinsics_list.h b/compiler/optimizing/intrinsics_list.h index 7e5339ec21..bfe5e55c56 100644 --- a/compiler/optimizing/intrinsics_list.h +++ b/compiler/optimizing/intrinsics_list.h @@ -29,9 +29,15 @@ V(IntegerReverse, kStatic, kNeedsEnvironmentOrCache) \ V(IntegerReverseBytes, kStatic, kNeedsEnvironmentOrCache) \ V(IntegerNumberOfLeadingZeros, kStatic, kNeedsEnvironmentOrCache) \ + V(IntegerNumberOfTrailingZeros, kStatic, kNeedsEnvironmentOrCache) \ + V(IntegerRotateRight, kStatic, kNeedsEnvironmentOrCache) \ + V(IntegerRotateLeft, kStatic, kNeedsEnvironmentOrCache) \ V(LongReverse, kStatic, kNeedsEnvironmentOrCache) \ V(LongReverseBytes, kStatic, kNeedsEnvironmentOrCache) \ V(LongNumberOfLeadingZeros, kStatic, kNeedsEnvironmentOrCache) \ + V(LongNumberOfTrailingZeros, kStatic, kNeedsEnvironmentOrCache) \ + V(LongRotateRight, kStatic, kNeedsEnvironmentOrCache) \ + V(LongRotateLeft, kStatic, kNeedsEnvironmentOrCache) \ V(ShortReverseBytes, kStatic, kNeedsEnvironmentOrCache) \ V(MathAbsDouble, kStatic, kNeedsEnvironmentOrCache) \ V(MathAbsFloat, kStatic, kNeedsEnvironmentOrCache) \ diff --git a/compiler/optimizing/intrinsics_x86.cc b/compiler/optimizing/intrinsics_x86.cc index be076cd3ff..bff29af542 100644 --- a/compiler/optimizing/intrinsics_x86.cc +++ b/compiler/optimizing/intrinsics_x86.cc @@ -1957,6 +1957,12 @@ UNIMPLEMENTED_INTRINSIC(MathRoundDouble) UNIMPLEMENTED_INTRINSIC(StringGetCharsNoCheck) UNIMPLEMENTED_INTRINSIC(SystemArrayCopyChar) UNIMPLEMENTED_INTRINSIC(ReferenceGetReferent) +UNIMPLEMENTED_INTRINSIC(IntegerNumberOfTrailingZeros) +UNIMPLEMENTED_INTRINSIC(LongNumberOfTrailingZeros) +UNIMPLEMENTED_INTRINSIC(IntegerRotateRight) +UNIMPLEMENTED_INTRINSIC(LongRotateRight) +UNIMPLEMENTED_INTRINSIC(IntegerRotateLeft) +UNIMPLEMENTED_INTRINSIC(LongRotateLeft) #undef UNIMPLEMENTED_INTRINSIC diff --git a/compiler/optimizing/intrinsics_x86_64.cc b/compiler/optimizing/intrinsics_x86_64.cc index 1f35b597fe..f91ad7fe94 100644 --- a/compiler/optimizing/intrinsics_x86_64.cc +++ b/compiler/optimizing/intrinsics_x86_64.cc @@ -1775,6 +1775,12 @@ void IntrinsicCodeGeneratorX86_64::Visit ## Name(HInvoke* invoke ATTRIBUTE_UNUSE UNIMPLEMENTED_INTRINSIC(StringGetCharsNoCheck) UNIMPLEMENTED_INTRINSIC(SystemArrayCopyChar) UNIMPLEMENTED_INTRINSIC(ReferenceGetReferent) +UNIMPLEMENTED_INTRINSIC(IntegerNumberOfTrailingZeros) +UNIMPLEMENTED_INTRINSIC(LongNumberOfTrailingZeros) +UNIMPLEMENTED_INTRINSIC(IntegerRotateRight) +UNIMPLEMENTED_INTRINSIC(LongRotateRight) +UNIMPLEMENTED_INTRINSIC(IntegerRotateLeft) +UNIMPLEMENTED_INTRINSIC(LongRotateLeft) #undef UNIMPLEMENTED_INTRINSIC diff --git a/compiler/utils/arm/assembler_arm.h b/compiler/utils/arm/assembler_arm.h index 7825457d5c..4585d718bf 100644 --- a/compiler/utils/arm/assembler_arm.h +++ b/compiler/utils/arm/assembler_arm.h @@ -495,6 +495,7 @@ class ArmAssembler : public Assembler { virtual void clz(Register rd, Register rm, Condition cond = AL) = 0; 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; // 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 d91ddee9b9..64fa9a4c0d 100644 --- a/compiler/utils/arm/assembler_arm32.cc +++ b/compiler/utils/arm/assembler_arm32.cc @@ -735,6 +735,20 @@ void Arm32Assembler::movt(Register rd, uint16_t imm16, Condition cond) { } +void Arm32Assembler::rbit(Register rd, Register rm, Condition cond) { + 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>(cond) << kConditionShift) | + B26 | B25 | B23 | B22 | B21 | B20 | (0xf << 16) | + (static_cast<int32_t>(rd) << kRdShift) | + (0xf << 8) | B5 | B4 | static_cast<int32_t>(rm); + Emit(encoding); +} + + 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 b96bb74182..6605afa598 100644 --- a/compiler/utils/arm/assembler_arm32.h +++ b/compiler/utils/arm/assembler_arm32.h @@ -87,6 +87,7 @@ class Arm32Assembler FINAL : public ArmAssembler { void clz(Register rd, Register rm, Condition cond = AL) OVERRIDE; 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; // Multiply instructions. void mul(Register rd, Register rn, Register rm, Condition cond = AL) OVERRIDE; diff --git a/compiler/utils/arm/assembler_arm32_test.cc b/compiler/utils/arm/assembler_arm32_test.cc index e6412ac684..2a0912e02d 100644 --- a/compiler/utils/arm/assembler_arm32_test.cc +++ b/compiler/utils/arm/assembler_arm32_test.cc @@ -883,4 +883,8 @@ TEST_F(AssemblerArm32Test, strexd) { DriverStr(expected, "strexd"); } +TEST_F(AssemblerArm32Test, rbit) { + T3Helper(&arm::Arm32Assembler::rbit, true, "rbit{cond} {reg1}, {reg2}", "rbit"); +} + } // namespace art diff --git a/compiler/utils/arm/assembler_thumb2.cc b/compiler/utils/arm/assembler_thumb2.cc index 90ed10c498..b76068b9d5 100644 --- a/compiler/utils/arm/assembler_thumb2.cc +++ b/compiler/utils/arm/assembler_thumb2.cc @@ -2426,6 +2426,25 @@ void Thumb2Assembler::movt(Register rd, uint16_t imm16, Condition cond) { } +void Thumb2Assembler::rbit(Register rd, Register rm, Condition cond) { + CHECK_NE(rd, kNoRegister); + CHECK_NE(rm, kNoRegister); + CheckCondition(cond); + CHECK_NE(rd, PC); + CHECK_NE(rm, PC); + CHECK_NE(rd, SP); + CHECK_NE(rm, SP); + int32_t encoding = B31 | B30 | B29 | B28 | B27 | + B25 | B23 | B20 | + static_cast<uint32_t>(rm) << 16 | + 0xf << 12 | + static_cast<uint32_t>(rd) << 8 | + B7 | B5 | + static_cast<uint32_t>(rm); + Emit32(encoding); +} + + void Thumb2Assembler::ldrex(Register rt, Register rn, uint16_t imm, Condition cond) { CHECK_NE(rn, kNoRegister); CHECK_NE(rt, kNoRegister); diff --git a/compiler/utils/arm/assembler_thumb2.h b/compiler/utils/arm/assembler_thumb2.h index c802c27ea6..aaa7b352be 100644 --- a/compiler/utils/arm/assembler_thumb2.h +++ b/compiler/utils/arm/assembler_thumb2.h @@ -111,6 +111,7 @@ class Thumb2Assembler FINAL : public ArmAssembler { void clz(Register rd, Register rm, Condition cond = AL) OVERRIDE; 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; // Multiply instructions. void mul(Register rd, Register rn, Register rm, Condition cond = AL) OVERRIDE; diff --git a/compiler/utils/arm/assembler_thumb2_test.cc b/compiler/utils/arm/assembler_thumb2_test.cc index 84f5cb16fb..9c08ce017e 100644 --- a/compiler/utils/arm/assembler_thumb2_test.cc +++ b/compiler/utils/arm/assembler_thumb2_test.cc @@ -1019,4 +1019,12 @@ TEST_F(AssemblerThumb2Test, Clz) { DriverStr(expected, "clz"); } +TEST_F(AssemblerThumb2Test, rbit) { + __ rbit(arm::R1, arm::R0); + + const char* expected = "rbit r1, r0\n"; + + DriverStr(expected, "rbit"); +} + } // namespace art |