diff options
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/linker/arm/relative_patcher_arm_base.cc | 2 | ||||
| -rw-r--r-- | compiler/optimizing/emit_swap_mips_test.cc | 4 | ||||
| -rw-r--r-- | compiler/optimizing/intrinsics_arm_vixl.cc | 143 |
3 files changed, 143 insertions, 6 deletions
diff --git a/compiler/linker/arm/relative_patcher_arm_base.cc b/compiler/linker/arm/relative_patcher_arm_base.cc index 18ff1c9bb6..4ca5afe177 100644 --- a/compiler/linker/arm/relative_patcher_arm_base.cc +++ b/compiler/linker/arm/relative_patcher_arm_base.cc @@ -28,7 +28,7 @@ namespace linker { class ArmBaseRelativePatcher::ThunkData { public: ThunkData(std::vector<uint8_t> code, uint32_t max_next_offset) - : code_(code), + : code_(std::move(code)), offsets_(), max_next_offset_(max_next_offset), pending_offset_(0u) { diff --git a/compiler/optimizing/emit_swap_mips_test.cc b/compiler/optimizing/emit_swap_mips_test.cc index 0d4e1c5c97..fa3c4dfba8 100644 --- a/compiler/optimizing/emit_swap_mips_test.cc +++ b/compiler/optimizing/emit_swap_mips_test.cc @@ -91,7 +91,9 @@ class EmitSwapMipsTest : public ::testing::Test { return nullptr; } - void DriverWrapper(HParallelMove* move, std::string assembly_text, std::string test_name) { + void DriverWrapper(HParallelMove* move, + const std::string& assembly_text, + const std::string& test_name) { codegen_->GetMoveResolver()->EmitNativeCode(move); assembler_ = codegen_->GetAssembler(); assembler_->FinalizeCode(); diff --git a/compiler/optimizing/intrinsics_arm_vixl.cc b/compiler/optimizing/intrinsics_arm_vixl.cc index 8b4044d69b..82a97bccb7 100644 --- a/compiler/optimizing/intrinsics_arm_vixl.cc +++ b/compiler/optimizing/intrinsics_arm_vixl.cc @@ -331,6 +331,14 @@ static void CreateIntToIntLocations(ArenaAllocator* arena, HInvoke* invoke) { locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); } +static void CreateIntToIntLocationsWithOverlap(ArenaAllocator* arena, HInvoke* invoke) { + LocationSummary* locations = new (arena) LocationSummary(invoke, + LocationSummary::kNoCall, + kIntrinsified); + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap); +} + static void CreateFPToFPLocations(ArenaAllocator* arena, HInvoke* invoke) { LocationSummary* locations = new (arena) LocationSummary(invoke, LocationSummary::kNoCall, @@ -2827,6 +2835,137 @@ void IntrinsicCodeGeneratorARMVIXL::VisitLongBitCount(HInvoke* invoke) { GenBitCount(invoke, Primitive::kPrimLong, GetAssembler()); } +static void GenHighestOneBit(HInvoke* invoke, + Primitive::Type type, + CodeGeneratorARMVIXL* codegen) { + DCHECK(Primitive::IsIntOrLongType(type)); + + ArmVIXLAssembler* assembler = codegen->GetAssembler(); + UseScratchRegisterScope temps(assembler->GetVIXLAssembler()); + const vixl32::Register temp = temps.Acquire(); + + if (type == Primitive::kPrimLong) { + LocationSummary* locations = invoke->GetLocations(); + Location in = locations->InAt(0); + Location out = locations->Out(); + + vixl32::Register in_reg_lo = LowRegisterFrom(in); + vixl32::Register in_reg_hi = HighRegisterFrom(in); + vixl32::Register out_reg_lo = LowRegisterFrom(out); + vixl32::Register out_reg_hi = HighRegisterFrom(out); + + __ Mov(temp, 0x80000000); // Modified immediate. + __ Clz(out_reg_lo, in_reg_lo); + __ Clz(out_reg_hi, in_reg_hi); + __ Lsr(out_reg_lo, temp, out_reg_lo); + __ Lsrs(out_reg_hi, temp, out_reg_hi); + + // Discard result for lowest 32 bits if highest 32 bits are not zero. + // Since IT blocks longer than a 16-bit instruction are deprecated by ARMv8, + // we check that the output is in a low register, so that a 16-bit MOV + // encoding can be used. If output is in a high register, then we generate + // 4 more bytes of code to avoid a branch. + Operand mov_src(0); + if (!out_reg_lo.IsLow()) { + __ Mov(LeaveFlags, temp, 0); + mov_src = Operand(temp); + } + ExactAssemblyScope it_scope(codegen->GetVIXLAssembler(), + 2 * vixl32::k16BitT32InstructionSizeInBytes, + CodeBufferCheckScope::kExactSize); + __ it(ne); + __ mov(ne, out_reg_lo, mov_src); + } else { + vixl32::Register out = OutputRegister(invoke); + vixl32::Register in = InputRegisterAt(invoke, 0); + + __ Mov(temp, 0x80000000); // Modified immediate. + __ Clz(out, in); + __ Lsr(out, temp, out); + } +} + +void IntrinsicLocationsBuilderARMVIXL::VisitIntegerHighestOneBit(HInvoke* invoke) { + CreateIntToIntLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorARMVIXL::VisitIntegerHighestOneBit(HInvoke* invoke) { + GenHighestOneBit(invoke, Primitive::kPrimInt, codegen_); +} + +void IntrinsicLocationsBuilderARMVIXL::VisitLongHighestOneBit(HInvoke* invoke) { + CreateIntToIntLocationsWithOverlap(arena_, invoke); +} + +void IntrinsicCodeGeneratorARMVIXL::VisitLongHighestOneBit(HInvoke* invoke) { + GenHighestOneBit(invoke, Primitive::kPrimLong, codegen_); +} + +static void GenLowestOneBit(HInvoke* invoke, + Primitive::Type type, + CodeGeneratorARMVIXL* codegen) { + DCHECK(Primitive::IsIntOrLongType(type)); + + ArmVIXLAssembler* assembler = codegen->GetAssembler(); + UseScratchRegisterScope temps(assembler->GetVIXLAssembler()); + const vixl32::Register temp = temps.Acquire(); + + if (type == Primitive::kPrimLong) { + LocationSummary* locations = invoke->GetLocations(); + Location in = locations->InAt(0); + Location out = locations->Out(); + + vixl32::Register in_reg_lo = LowRegisterFrom(in); + vixl32::Register in_reg_hi = HighRegisterFrom(in); + vixl32::Register out_reg_lo = LowRegisterFrom(out); + vixl32::Register out_reg_hi = HighRegisterFrom(out); + + __ Rsb(out_reg_hi, in_reg_hi, 0); + __ Rsb(out_reg_lo, in_reg_lo, 0); + __ And(out_reg_hi, out_reg_hi, in_reg_hi); + // The result of this operation is 0 iff in_reg_lo is 0 + __ Ands(out_reg_lo, out_reg_lo, in_reg_lo); + + // Discard result for highest 32 bits if lowest 32 bits are not zero. + // Since IT blocks longer than a 16-bit instruction are deprecated by ARMv8, + // we check that the output is in a low register, so that a 16-bit MOV + // encoding can be used. If output is in a high register, then we generate + // 4 more bytes of code to avoid a branch. + Operand mov_src(0); + if (!out_reg_lo.IsLow()) { + __ Mov(LeaveFlags, temp, 0); + mov_src = Operand(temp); + } + ExactAssemblyScope it_scope(codegen->GetVIXLAssembler(), + 2 * vixl32::k16BitT32InstructionSizeInBytes, + CodeBufferCheckScope::kExactSize); + __ it(ne); + __ mov(ne, out_reg_hi, mov_src); + } else { + vixl32::Register out = OutputRegister(invoke); + vixl32::Register in = InputRegisterAt(invoke, 0); + + __ Rsb(temp, in, 0); + __ And(out, temp, in); + } +} + +void IntrinsicLocationsBuilderARMVIXL::VisitIntegerLowestOneBit(HInvoke* invoke) { + CreateIntToIntLocations(arena_, invoke); +} + +void IntrinsicCodeGeneratorARMVIXL::VisitIntegerLowestOneBit(HInvoke* invoke) { + GenLowestOneBit(invoke, Primitive::kPrimInt, codegen_); +} + +void IntrinsicLocationsBuilderARMVIXL::VisitLongLowestOneBit(HInvoke* invoke) { + CreateIntToIntLocationsWithOverlap(arena_, invoke); +} + +void IntrinsicCodeGeneratorARMVIXL::VisitLongLowestOneBit(HInvoke* invoke) { + GenLowestOneBit(invoke, Primitive::kPrimLong, codegen_); +} + void IntrinsicLocationsBuilderARMVIXL::VisitStringGetCharsNoCheck(HInvoke* invoke) { LocationSummary* locations = new (arena_) LocationSummary(invoke, LocationSummary::kNoCall, @@ -3124,10 +3263,6 @@ UNIMPLEMENTED_INTRINSIC(ARMVIXL, MathRoundDouble) // Could be done by changing UNIMPLEMENTED_INTRINSIC(ARMVIXL, UnsafeCASLong) // High register pressure. UNIMPLEMENTED_INTRINSIC(ARMVIXL, SystemArrayCopyChar) UNIMPLEMENTED_INTRINSIC(ARMVIXL, ReferenceGetReferent) -UNIMPLEMENTED_INTRINSIC(ARMVIXL, IntegerHighestOneBit) -UNIMPLEMENTED_INTRINSIC(ARMVIXL, LongHighestOneBit) -UNIMPLEMENTED_INTRINSIC(ARMVIXL, IntegerLowestOneBit) -UNIMPLEMENTED_INTRINSIC(ARMVIXL, LongLowestOneBit) UNIMPLEMENTED_INTRINSIC(ARMVIXL, StringStringIndexOf); UNIMPLEMENTED_INTRINSIC(ARMVIXL, StringStringIndexOfAfter); |