From 7500e5077caaddf84e26a4c2356fb69f3edc7be5 Mon Sep 17 00:00:00 2001 From: bmeurer Date: Wed, 5 Oct 2016 06:07:04 -0700 Subject: [PATCH] [turbofan][x64] Improve code generation for external reference access. Properly fold external reference access into memory operands whenever possible, i.e. for accessing the allocation top/limit, similar to what we do in Crankshaft and hand-written native code. This only works when the serializer is disabled, i.e. doesn't apply to the stubs in the snapshot (for now). This reduces register pressure especially around allocations where we'd currently need two registers to hold both the allocation top and limit pointers in registers (on x64). R=epertoso@chromium.org Review-Url: https://codereview.chromium.org/2398603002 Cr-Commit-Position: refs/heads/master@{#39993} --- src/compiler/instruction-selector.cc | 10 +++++++++- src/compiler/instruction-selector.h | 10 +++++++++- src/compiler/pipeline.cc | 10 +++++++++- src/compiler/x64/code-generator-x64.cc | 5 +++++ src/compiler/x64/instruction-codes-x64.h | 3 ++- src/compiler/x64/instruction-selector-x64.cc | 19 +++++++++++++++++++ 6 files changed, 53 insertions(+), 4 deletions(-) diff --git a/src/compiler/instruction-selector.cc b/src/compiler/instruction-selector.cc index e8a3153f7f..b150725b2b 100644 --- a/src/compiler/instruction-selector.cc +++ b/src/compiler/instruction-selector.cc @@ -23,7 +23,8 @@ InstructionSelector::InstructionSelector( InstructionSequence* sequence, Schedule* schedule, SourcePositionTable* source_positions, Frame* frame, SourcePositionMode source_position_mode, Features features, - EnableScheduling enable_scheduling) + EnableScheduling enable_scheduling, + EnableSerialization enable_serialization) : zone_(zone), linkage_(linkage), sequence_(sequence), @@ -41,6 +42,7 @@ InstructionSelector::InstructionSelector( virtual_register_rename_(zone), scheduler_(nullptr), enable_scheduling_(enable_scheduling), + enable_serialization_(enable_serialization), frame_(frame), instruction_selection_failed_(false) { instructions_.reserve(node_count); @@ -389,6 +391,12 @@ void InstructionSelector::SetEffectLevel(Node* node, int effect_level) { effect_level_[id] = effect_level; } +bool InstructionSelector::CanAddressRelativeToRootsRegister() const { + return (enable_serialization_ == kDisableSerialization && + (linkage()->GetIncomingDescriptor()->flags() & + CallDescriptor::kCanUseRoots)); +} + void InstructionSelector::MarkAsRepresentation(MachineRepresentation rep, const InstructionOperand& op) { UnallocatedOperand unalloc = UnallocatedOperand::cast(op); diff --git a/src/compiler/instruction-selector.h b/src/compiler/instruction-selector.h index 212a66eadb..2981f90a1c 100644 --- a/src/compiler/instruction-selector.h +++ b/src/compiler/instruction-selector.h @@ -49,6 +49,7 @@ class InstructionSelector final { enum SourcePositionMode { kCallSourcePositions, kAllSourcePositions }; enum EnableScheduling { kDisableScheduling, kEnableScheduling }; + enum EnableSerialization { kDisableSerialization, kEnableSerialization }; InstructionSelector( Zone* zone, size_t node_count, Linkage* linkage, @@ -58,7 +59,8 @@ class InstructionSelector final { Features features = SupportedFeatures(), EnableScheduling enable_scheduling = FLAG_turbo_instruction_scheduling ? kEnableScheduling - : kDisableScheduling); + : kDisableScheduling, + EnableSerialization enable_serialization = kDisableSerialization); // Visit code for the entire graph with the included schedule. bool SelectInstructions(); @@ -198,6 +200,11 @@ class InstructionSelector final { int GetVirtualRegister(const Node* node); const std::map GetVirtualRegistersForTesting() const; + // Check if we can generate loads and stores of ExternalConstants relative + // to the roots register, i.e. if both a root register is available for this + // compilation unit and the serializer is disabled. + bool CanAddressRelativeToRootsRegister() const; + Isolate* isolate() const { return sequence()->isolate(); } private: @@ -355,6 +362,7 @@ class InstructionSelector final { IntVector virtual_register_rename_; InstructionScheduler* scheduler_; EnableScheduling enable_scheduling_; + EnableSerialization enable_serialization_; Frame* frame_; bool instruction_selection_failed_; }; diff --git a/src/compiler/pipeline.cc b/src/compiler/pipeline.cc index 215104e54f..805b687e7d 100644 --- a/src/compiler/pipeline.cc +++ b/src/compiler/pipeline.cc @@ -1233,7 +1233,14 @@ struct InstructionSelectionPhase { data->schedule(), data->source_positions(), data->frame(), data->info()->is_source_positions_enabled() ? InstructionSelector::kAllSourcePositions - : InstructionSelector::kCallSourcePositions); + : InstructionSelector::kCallSourcePositions, + InstructionSelector::SupportedFeatures(), + FLAG_turbo_instruction_scheduling + ? InstructionSelector::kEnableScheduling + : InstructionSelector::kDisableScheduling, + data->info()->will_serialize() + ? InstructionSelector::kEnableSerialization + : InstructionSelector::kDisableSerialization); if (!selector.SelectInstructions()) { data->set_compilation_failed(); } @@ -1635,6 +1642,7 @@ Handle Pipeline::GenerateCodeForCodeStub(Isolate* isolate, Code::Flags flags, const char* debug_name) { CompilationInfo info(CStrVector(debug_name), isolate, graph->zone(), flags); + if (isolate->serializer_enabled()) info.PrepareForSerializing(); // Construct a pipeline for scheduling and code generation. ZonePool zone_pool(isolate->allocator()); diff --git a/src/compiler/x64/code-generator-x64.cc b/src/compiler/x64/code-generator-x64.cc index 56cd3ea025..4d63e9ad83 100644 --- a/src/compiler/x64/code-generator-x64.cc +++ b/src/compiler/x64/code-generator-x64.cc @@ -133,6 +133,11 @@ class X64OperandConverter : public InstructionOperandConverter { int32_t disp = InputInt32(NextOffset(offset)); return Operand(index, scale, disp); } + case kMode_Root: { + Register base = kRootRegister; + int32_t disp = InputInt32(NextOffset(offset)); + return Operand(base, disp); + } case kMode_None: UNREACHABLE(); return Operand(no_reg, 0); diff --git a/src/compiler/x64/instruction-codes-x64.h b/src/compiler/x64/instruction-codes-x64.h index c92522dbfa..35acec08dc 100644 --- a/src/compiler/x64/instruction-codes-x64.h +++ b/src/compiler/x64/instruction-codes-x64.h @@ -180,7 +180,8 @@ namespace compiler { V(M1I) /* [ %r2*1 + K] */ \ V(M2I) /* [ %r2*2 + K] */ \ V(M4I) /* [ %r2*4 + K] */ \ - V(M8I) /* [ %r2*8 + K] */ + V(M8I) /* [ %r2*8 + K] */ \ + V(Root) /* [%root + K] */ } // namespace compiler } // namespace internal diff --git a/src/compiler/x64/instruction-selector-x64.cc b/src/compiler/x64/instruction-selector-x64.cc index bfe7c62649..9a7657ef32 100644 --- a/src/compiler/x64/instruction-selector-x64.cc +++ b/src/compiler/x64/instruction-selector-x64.cc @@ -136,6 +136,22 @@ class X64OperandGenerator final : public OperandGenerator { AddressingMode GetEffectiveAddressMemoryOperand(Node* operand, InstructionOperand inputs[], size_t* input_count) { + if (selector()->CanAddressRelativeToRootsRegister()) { + LoadMatcher m(operand); + if (m.index().HasValue() && m.object().HasValue()) { + Address const kRootsRegisterValue = + kRootRegisterBias + + reinterpret_cast
( + selector()->isolate()->heap()->roots_array_start()); + ptrdiff_t const delta = + m.index().Value() + + (m.object().Value().address() - kRootsRegisterValue); + if (is_int32(delta)) { + inputs[(*input_count)++] = TempImmediate(static_cast(delta)); + return kMode_Root; + } + } + } BaseWithIndexAndDisplacement64Matcher m(operand, AddressOption::kAllowAll); DCHECK(m.matches()); if ((m.displacement() == nullptr || CanBeImmediate(m.displacement()))) { @@ -155,6 +171,7 @@ class X64OperandGenerator final : public OperandGenerator { }; namespace { + ArchOpcode GetLoadOpcode(LoadRepresentation load_rep) { ArchOpcode opcode = kArchNop; switch (load_rep.representation()) { @@ -187,6 +204,7 @@ ArchOpcode GetLoadOpcode(LoadRepresentation load_rep) { } return opcode; } + } // namespace void InstructionSelector::VisitLoad(Node* node) { @@ -723,6 +741,7 @@ bool TryMatchLoadWord64AndShiftRight(InstructionSelector* selector, Node* node, case kMode_M2I: case kMode_M4I: case kMode_M8I: + case kMode_Root: UNREACHABLE(); } inputs[input_count++] = ImmediateOperand(ImmediateOperand::INLINE, 4);