diff options
Diffstat (limited to 'compiler/optimizing')
-rw-r--r-- | compiler/optimizing/code_generator.cc | 3 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_x86.cc | 60 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_x86.h | 28 | ||||
-rw-r--r-- | compiler/optimizing/intrinsics_x86.cc | 120 |
4 files changed, 169 insertions, 42 deletions
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc index 6bfdacfb7f..901424f570 100644 --- a/compiler/optimizing/code_generator.cc +++ b/compiler/optimizing/code_generator.cc @@ -1688,8 +1688,7 @@ void CodeGenerator::ValidateInvokeRuntimeWithoutRecordingPcInfo(HInstruction* in instruction->IsLoadString() || instruction->IsInstanceOf() || instruction->IsCheckCast() || - (instruction->IsInvokeVirtual() && instruction->GetLocations()->Intrinsified()) || - (instruction->IsInvokeStaticOrDirect() && instruction->GetLocations()->Intrinsified())) + (instruction->IsInvoke() && instruction->GetLocations()->Intrinsified())) << "instruction->DebugName()=" << instruction->DebugName() << " slow_path->GetDescription()=" << slow_path->GetDescription(); } diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index 04123cf70e..370b839764 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -489,8 +489,7 @@ class ReadBarrierMarkSlowPathX86 : public SlowPathCode { instruction_->IsLoadString() || instruction_->IsInstanceOf() || instruction_->IsCheckCast() || - (instruction_->IsInvokeVirtual() && instruction_->GetLocations()->Intrinsified()) || - (instruction_->IsInvokeStaticOrDirect() && instruction_->GetLocations()->Intrinsified())) + (instruction_->IsInvoke() && instruction_->GetLocations()->Intrinsified())) << "Unexpected instruction in read barrier marking slow path: " << instruction_->DebugName(); @@ -1439,6 +1438,63 @@ void CodeGeneratorX86::Move64(Location destination, Location source) { } } +static Address CreateAddress(Register base, + Register index = Register::kNoRegister, + ScaleFactor scale = TIMES_1, + int32_t disp = 0) { + if (index == Register::kNoRegister) { + return Address(base, disp); + } + + return Address(base, index, scale, disp); +} + +void CodeGeneratorX86::MoveFromMemory(DataType::Type dst_type, + Location dst, + Register src_base, + Register src_index, + ScaleFactor src_scale, + int32_t src_disp) { + DCHECK(src_base != Register::kNoRegister); + Address src = CreateAddress(src_base, src_index, src_scale, src_disp); + + switch (dst_type) { + case DataType::Type::kBool: + case DataType::Type::kUint8: + __ movzxb(dst.AsRegister<Register>(), src); + break; + case DataType::Type::kInt8: + __ movsxb(dst.AsRegister<Register>(), src); + break; + case DataType::Type::kInt16: + __ movsxw(dst.AsRegister<Register>(), src); + break; + case DataType::Type::kUint16: + __ movzxw(dst.AsRegister<Register>(), src); + break; + case DataType::Type::kInt32: + case DataType::Type::kUint32: + __ movl(dst.AsRegister<Register>(), src); + break; + case DataType::Type::kInt64: + case DataType::Type::kUint64: { + Address src_next_4_bytes = CreateAddress(src_base, src_index, src_scale, src_disp + 4); + __ movl(dst.AsRegisterPairLow<Register>(), src); + __ movl(dst.AsRegisterPairHigh<Register>(), src_next_4_bytes); + break; + } + case DataType::Type::kFloat32: + __ movss(dst.AsFpuRegister<XmmRegister>(), src); + break; + case DataType::Type::kFloat64: + __ movsd(dst.AsFpuRegister<XmmRegister>(), src); + break; + case DataType::Type::kVoid: + case DataType::Type::kReference: + LOG(FATAL) << "Unreachable type " << dst_type; + } +} + void CodeGeneratorX86::MoveConstant(Location location, int32_t value) { DCHECK(location.IsRegister()); __ movl(location.AsRegister<Register>(), Immediate(value)); diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h index d2f1e774b7..ce25849cf5 100644 --- a/compiler/optimizing/code_generator_x86.h +++ b/compiler/optimizing/code_generator_x86.h @@ -232,6 +232,17 @@ class InstructionCodeGeneratorX86 : public InstructionCodeGenerator { // generates less code/data with a small num_entries. static constexpr uint32_t kPackedSwitchJumpTableThreshold = 5; + // Generate a GC root reference load: + // + // root <- *address + // + // while honoring read barriers based on read_barrier_option. + void GenerateGcRootFieldLoad(HInstruction* instruction, + Location root, + const Address& address, + Label* fixup_label, + ReadBarrierOption read_barrier_option); + private: // Generate code for the given suspend check. If not null, `successor` // is the block to branch to if the suspend check is not needed, and after @@ -292,16 +303,6 @@ class InstructionCodeGeneratorX86 : public InstructionCodeGenerator { Location obj, uint32_t offset, ReadBarrierOption read_barrier_option); - // Generate a GC root reference load: - // - // root <- *address - // - // while honoring read barriers based on read_barrier_option. - void GenerateGcRootFieldLoad(HInstruction* instruction, - Location root, - const Address& address, - Label* fixup_label, - ReadBarrierOption read_barrier_option); // Push value to FPU stack. `is_fp` specifies whether the value is floating point or not. // `is_wide` specifies whether it is long/double or not. @@ -433,6 +434,13 @@ class CodeGeneratorX86 : public CodeGenerator { void Move32(Location destination, Location source); // Helper method to move a 64bits value between two locations. void Move64(Location destination, Location source); + // Helper method to move a value from an address to a register. + void MoveFromMemory(DataType::Type dst_type, + Location dst, + Register src_base, + Register src_index = Register::kNoRegister, + ScaleFactor src_scale = TIMES_1, + int32_t src_disp = 0); // Check if the desired_string_load_kind is supported. If it is, return it, // otherwise return a fall-back kind that should be used instead. diff --git a/compiler/optimizing/intrinsics_x86.cc b/compiler/optimizing/intrinsics_x86.cc index 7bd6b04ba5..2fdea7668a 100644 --- a/compiler/optimizing/intrinsics_x86.cc +++ b/compiler/optimizing/intrinsics_x86.cc @@ -22,6 +22,7 @@ #include "art_method.h" #include "base/bit_utils.h" #include "code_generator_x86.h" +#include "data_type-inl.h" #include "entrypoints/quick/quick_entrypoints.h" #include "heap_poisoning.h" #include "intrinsics.h" @@ -3065,55 +3066,118 @@ void IntrinsicCodeGeneratorX86::VisitIntegerDivideUnsigned(HInvoke* invoke) { __ Bind(slow_path->GetExitLabel()); } -static void CreateVarHandleLocationSummary(HInvoke* invoke, ArenaAllocator* allocator) { - InvokeDexCallingConventionVisitorX86 visitor; - LocationSummary* locations = - new (allocator) LocationSummary(invoke, LocationSummary::kCallOnMainAndSlowPath, kIntrinsified); +void IntrinsicLocationsBuilderX86::VisitVarHandleGet(HInvoke* invoke) { + // The only read barrier implementation supporting the + // VarHandleGet intrinsic is the Baker-style read barriers. + if (kEmitCompilerReadBarrier && !kUseBakerReadBarrier) { + return; + } + + DataType::Type type = invoke->GetType(); - for (size_t i = 0; i < invoke->GetNumberOfArguments(); i++) { - HInstruction* input = invoke->InputAt(i); - locations->SetInAt(i, visitor.GetNextLocation(input->GetType())); + if (type == DataType::Type::kVoid) { + // Return type should not be void for get. + return; } - locations->SetOut(visitor.GetReturnLocation(invoke->GetType())); -} + if (type == DataType::Type::kReference) { + // Reference return type is not implemented yet + // TODO: implement for kReference + return; + } -#define INTRINSIC_VARHANDLE_LOCATIONS_BUILDER(Name) \ -void IntrinsicLocationsBuilderX86::Visit ## Name(HInvoke* invoke) { \ - CreateVarHandleLocationSummary(invoke, allocator_); \ + if (invoke->GetNumberOfArguments() == 1u) { + // Static field get + ArenaAllocator* allocator = invoke->GetBlock()->GetGraph()->GetAllocator(); + LocationSummary* locations = new (allocator) LocationSummary( + invoke, LocationSummary::kCallOnSlowPath, kIntrinsified); + locations->SetInAt(0, Location::RequiresRegister()); + locations->AddTemp(Location::RequiresRegister()); + + switch (DataType::Kind(type)) { + case DataType::Type::kInt64: + locations->AddTemp(Location::RequiresRegister()); + FALLTHROUGH_INTENDED; + case DataType::Type::kInt32: + locations->SetOut(Location::RequiresRegister()); + break; + default: + DCHECK(DataType::IsFloatingPointType(type)); + locations->AddTemp(Location::RequiresRegister()); + locations->SetOut(Location::RequiresFpuRegister()); + } + } + + // TODO: support instance fields, arrays, etc. } -INTRINSIC_VARHANDLE_LOCATIONS_BUILDER(VarHandleGet) +void IntrinsicCodeGeneratorX86::VisitVarHandleGet(HInvoke* invoke) { + // The only read barrier implementation supporting the + // VarHandleGet intrinsic is the Baker-style read barriers. + DCHECK(!kEmitCompilerReadBarrier || kUseBakerReadBarrier); -static void GenerateVarHandleCode(HInvoke* invoke, CodeGeneratorX86* codegen) { - X86Assembler* assembler = codegen->GetAssembler(); - Register varhandle_object = invoke->GetLocations()->InAt(0).AsRegister<Register>(); + X86Assembler* assembler = codegen_->GetAssembler(); + LocationSummary* locations = invoke->GetLocations(); + Register varhandle_object = locations->InAt(0).AsRegister<Register>(); const uint32_t access_modes_bitmask_offset = mirror::VarHandle::AccessModesBitMaskOffset().Uint32Value(); mirror::VarHandle::AccessMode access_mode = mirror::VarHandle::GetAccessModeByIntrinsic(invoke->GetIntrinsic()); const uint32_t access_mode_bit = 1u << static_cast<uint32_t>(access_mode); + const uint32_t var_type_offset = mirror::VarHandle::VarTypeOffset().Uint32Value(); + const uint32_t coordtype0_offset = mirror::VarHandle::CoordinateType0Offset().Uint32Value(); + const uint32_t primitive_type_offset = mirror::Class::PrimitiveTypeOffset().Uint32Value(); + DataType::Type type = invoke->GetType(); + // For now, only primitive types are supported + DCHECK_NE(type, DataType::Type::kVoid); + DCHECK_NE(type, DataType::Type::kReference); + uint32_t primitive_type = static_cast<uint32_t>(DataTypeToPrimitive(type)); + Register temp = locations->GetTemp(0).AsRegister<Register>(); // If the access mode is not supported, bail to runtime implementation to handle __ testl(Address(varhandle_object, access_modes_bitmask_offset), Immediate(access_mode_bit)); - SlowPathCode* slow_path = new (codegen->GetScopedAllocator()) IntrinsicSlowPathX86(invoke); - codegen->AddSlowPath(slow_path); + SlowPathCode* slow_path = new (codegen_->GetScopedAllocator()) IntrinsicSlowPathX86(invoke); + codegen_->AddSlowPath(slow_path); __ j(kZero, slow_path->GetEntryLabel()); - // For now, none of the access modes are compiled. The runtime handles them on - // both slow path and main path. - // TODO: replace calling the runtime with actual assembly code - codegen->GenerateInvokePolymorphicCall(invoke->AsInvokePolymorphic()); + // Check the varType.primitiveType against the type we're trying to retrieve. We do not need a + // read barrier when loading a reference only for loading constant field through the reference. + __ movl(temp, Address(varhandle_object, var_type_offset)); + __ MaybeUnpoisonHeapReference(temp); + __ cmpw(Address(temp, primitive_type_offset), Immediate(primitive_type)); + __ j(kNotEqual, slow_path->GetEntryLabel()); - __ Bind(slow_path->GetExitLabel()); -} + // Check that the varhandle references a static field by checking that coordinateType0 == null. + // Do not emit read barrier (or unpoison the reference) for comparing to null. + __ cmpl(Address(varhandle_object, coordtype0_offset), Immediate(0)); + __ j(kNotEqual, slow_path->GetEntryLabel()); -#define INTRINSIC_VARHANDLE_CODE_GENERATOR(Name) \ -void IntrinsicCodeGeneratorX86::Visit ## Name(HInvoke* invoke) { \ - GenerateVarHandleCode(invoke, codegen_); \ + Location out = locations->Out(); + // Use 'out' as a temporary register if it's a core register + Register offset = + out.IsRegister() ? out.AsRegister<Register>() : locations->GetTemp(1).AsRegister<Register>(); + const uint32_t artfield_offset = mirror::FieldVarHandle::ArtFieldOffset().Uint32Value(); + const uint32_t offset_offset = ArtField::OffsetOffset().Uint32Value(); + const uint32_t declaring_class_offset = ArtField::DeclaringClassOffset().Uint32Value(); + + // Load the ArtField, the offset and declaring class + __ movl(temp, Address(varhandle_object, artfield_offset)); + __ movl(offset, Address(temp, offset_offset)); + InstructionCodeGeneratorX86* instr_codegen = + down_cast<InstructionCodeGeneratorX86*>(codegen_->GetInstructionVisitor()); + instr_codegen->GenerateGcRootFieldLoad(invoke, + Location::RegisterLocation(temp), + Address(temp, declaring_class_offset), + /* fixup_label= */ nullptr, + kCompilerReadBarrierOption); + + // Load the value from the field + CodeGeneratorX86* codegen_x86 = down_cast<CodeGeneratorX86*>(codegen_); + codegen_x86->MoveFromMemory(type, out, temp, offset); + + __ Bind(slow_path->GetExitLabel()); } -INTRINSIC_VARHANDLE_CODE_GENERATOR(VarHandleGet) UNIMPLEMENTED_INTRINSIC(X86, MathRoundDouble) UNIMPLEMENTED_INTRINSIC(X86, ReferenceGetReferent) |