summaryrefslogtreecommitdiff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/linker/arm/relative_patcher_arm_base.cc2
-rw-r--r--compiler/optimizing/emit_swap_mips_test.cc4
-rw-r--r--compiler/optimizing/intrinsics_arm_vixl.cc143
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);