Commit 7500e507 authored by bmeurer's avatar bmeurer Committed by Commit bot

[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}
parent c22e4278
...@@ -23,7 +23,8 @@ InstructionSelector::InstructionSelector( ...@@ -23,7 +23,8 @@ InstructionSelector::InstructionSelector(
InstructionSequence* sequence, Schedule* schedule, InstructionSequence* sequence, Schedule* schedule,
SourcePositionTable* source_positions, Frame* frame, SourcePositionTable* source_positions, Frame* frame,
SourcePositionMode source_position_mode, Features features, SourcePositionMode source_position_mode, Features features,
EnableScheduling enable_scheduling) EnableScheduling enable_scheduling,
EnableSerialization enable_serialization)
: zone_(zone), : zone_(zone),
linkage_(linkage), linkage_(linkage),
sequence_(sequence), sequence_(sequence),
...@@ -41,6 +42,7 @@ InstructionSelector::InstructionSelector( ...@@ -41,6 +42,7 @@ InstructionSelector::InstructionSelector(
virtual_register_rename_(zone), virtual_register_rename_(zone),
scheduler_(nullptr), scheduler_(nullptr),
enable_scheduling_(enable_scheduling), enable_scheduling_(enable_scheduling),
enable_serialization_(enable_serialization),
frame_(frame), frame_(frame),
instruction_selection_failed_(false) { instruction_selection_failed_(false) {
instructions_.reserve(node_count); instructions_.reserve(node_count);
...@@ -389,6 +391,12 @@ void InstructionSelector::SetEffectLevel(Node* node, int effect_level) { ...@@ -389,6 +391,12 @@ void InstructionSelector::SetEffectLevel(Node* node, int effect_level) {
effect_level_[id] = 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, void InstructionSelector::MarkAsRepresentation(MachineRepresentation rep,
const InstructionOperand& op) { const InstructionOperand& op) {
UnallocatedOperand unalloc = UnallocatedOperand::cast(op); UnallocatedOperand unalloc = UnallocatedOperand::cast(op);
......
...@@ -49,6 +49,7 @@ class InstructionSelector final { ...@@ -49,6 +49,7 @@ class InstructionSelector final {
enum SourcePositionMode { kCallSourcePositions, kAllSourcePositions }; enum SourcePositionMode { kCallSourcePositions, kAllSourcePositions };
enum EnableScheduling { kDisableScheduling, kEnableScheduling }; enum EnableScheduling { kDisableScheduling, kEnableScheduling };
enum EnableSerialization { kDisableSerialization, kEnableSerialization };
InstructionSelector( InstructionSelector(
Zone* zone, size_t node_count, Linkage* linkage, Zone* zone, size_t node_count, Linkage* linkage,
...@@ -58,7 +59,8 @@ class InstructionSelector final { ...@@ -58,7 +59,8 @@ class InstructionSelector final {
Features features = SupportedFeatures(), Features features = SupportedFeatures(),
EnableScheduling enable_scheduling = FLAG_turbo_instruction_scheduling EnableScheduling enable_scheduling = FLAG_turbo_instruction_scheduling
? kEnableScheduling ? kEnableScheduling
: kDisableScheduling); : kDisableScheduling,
EnableSerialization enable_serialization = kDisableSerialization);
// Visit code for the entire graph with the included schedule. // Visit code for the entire graph with the included schedule.
bool SelectInstructions(); bool SelectInstructions();
...@@ -198,6 +200,11 @@ class InstructionSelector final { ...@@ -198,6 +200,11 @@ class InstructionSelector final {
int GetVirtualRegister(const Node* node); int GetVirtualRegister(const Node* node);
const std::map<NodeId, int> GetVirtualRegistersForTesting() const; const std::map<NodeId, int> 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(); } Isolate* isolate() const { return sequence()->isolate(); }
private: private:
...@@ -355,6 +362,7 @@ class InstructionSelector final { ...@@ -355,6 +362,7 @@ class InstructionSelector final {
IntVector virtual_register_rename_; IntVector virtual_register_rename_;
InstructionScheduler* scheduler_; InstructionScheduler* scheduler_;
EnableScheduling enable_scheduling_; EnableScheduling enable_scheduling_;
EnableSerialization enable_serialization_;
Frame* frame_; Frame* frame_;
bool instruction_selection_failed_; bool instruction_selection_failed_;
}; };
......
...@@ -1233,7 +1233,14 @@ struct InstructionSelectionPhase { ...@@ -1233,7 +1233,14 @@ struct InstructionSelectionPhase {
data->schedule(), data->source_positions(), data->frame(), data->schedule(), data->source_positions(), data->frame(),
data->info()->is_source_positions_enabled() data->info()->is_source_positions_enabled()
? InstructionSelector::kAllSourcePositions ? 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()) { if (!selector.SelectInstructions()) {
data->set_compilation_failed(); data->set_compilation_failed();
} }
...@@ -1635,6 +1642,7 @@ Handle<Code> Pipeline::GenerateCodeForCodeStub(Isolate* isolate, ...@@ -1635,6 +1642,7 @@ Handle<Code> Pipeline::GenerateCodeForCodeStub(Isolate* isolate,
Code::Flags flags, Code::Flags flags,
const char* debug_name) { const char* debug_name) {
CompilationInfo info(CStrVector(debug_name), isolate, graph->zone(), flags); CompilationInfo info(CStrVector(debug_name), isolate, graph->zone(), flags);
if (isolate->serializer_enabled()) info.PrepareForSerializing();
// Construct a pipeline for scheduling and code generation. // Construct a pipeline for scheduling and code generation.
ZonePool zone_pool(isolate->allocator()); ZonePool zone_pool(isolate->allocator());
......
...@@ -133,6 +133,11 @@ class X64OperandConverter : public InstructionOperandConverter { ...@@ -133,6 +133,11 @@ class X64OperandConverter : public InstructionOperandConverter {
int32_t disp = InputInt32(NextOffset(offset)); int32_t disp = InputInt32(NextOffset(offset));
return Operand(index, scale, disp); return Operand(index, scale, disp);
} }
case kMode_Root: {
Register base = kRootRegister;
int32_t disp = InputInt32(NextOffset(offset));
return Operand(base, disp);
}
case kMode_None: case kMode_None:
UNREACHABLE(); UNREACHABLE();
return Operand(no_reg, 0); return Operand(no_reg, 0);
......
...@@ -180,7 +180,8 @@ namespace compiler { ...@@ -180,7 +180,8 @@ namespace compiler {
V(M1I) /* [ %r2*1 + K] */ \ V(M1I) /* [ %r2*1 + K] */ \
V(M2I) /* [ %r2*2 + K] */ \ V(M2I) /* [ %r2*2 + K] */ \
V(M4I) /* [ %r2*4 + K] */ \ V(M4I) /* [ %r2*4 + K] */ \
V(M8I) /* [ %r2*8 + K] */ V(M8I) /* [ %r2*8 + K] */ \
V(Root) /* [%root + K] */
} // namespace compiler } // namespace compiler
} // namespace internal } // namespace internal
......
...@@ -136,6 +136,22 @@ class X64OperandGenerator final : public OperandGenerator { ...@@ -136,6 +136,22 @@ class X64OperandGenerator final : public OperandGenerator {
AddressingMode GetEffectiveAddressMemoryOperand(Node* operand, AddressingMode GetEffectiveAddressMemoryOperand(Node* operand,
InstructionOperand inputs[], InstructionOperand inputs[],
size_t* input_count) { size_t* input_count) {
if (selector()->CanAddressRelativeToRootsRegister()) {
LoadMatcher<ExternalReferenceMatcher> m(operand);
if (m.index().HasValue() && m.object().HasValue()) {
Address const kRootsRegisterValue =
kRootRegisterBias +
reinterpret_cast<Address>(
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<int32_t>(delta));
return kMode_Root;
}
}
}
BaseWithIndexAndDisplacement64Matcher m(operand, AddressOption::kAllowAll); BaseWithIndexAndDisplacement64Matcher m(operand, AddressOption::kAllowAll);
DCHECK(m.matches()); DCHECK(m.matches());
if ((m.displacement() == nullptr || CanBeImmediate(m.displacement()))) { if ((m.displacement() == nullptr || CanBeImmediate(m.displacement()))) {
...@@ -155,6 +171,7 @@ class X64OperandGenerator final : public OperandGenerator { ...@@ -155,6 +171,7 @@ class X64OperandGenerator final : public OperandGenerator {
}; };
namespace { namespace {
ArchOpcode GetLoadOpcode(LoadRepresentation load_rep) { ArchOpcode GetLoadOpcode(LoadRepresentation load_rep) {
ArchOpcode opcode = kArchNop; ArchOpcode opcode = kArchNop;
switch (load_rep.representation()) { switch (load_rep.representation()) {
...@@ -187,6 +204,7 @@ ArchOpcode GetLoadOpcode(LoadRepresentation load_rep) { ...@@ -187,6 +204,7 @@ ArchOpcode GetLoadOpcode(LoadRepresentation load_rep) {
} }
return opcode; return opcode;
} }
} // namespace } // namespace
void InstructionSelector::VisitLoad(Node* node) { void InstructionSelector::VisitLoad(Node* node) {
...@@ -723,6 +741,7 @@ bool TryMatchLoadWord64AndShiftRight(InstructionSelector* selector, Node* node, ...@@ -723,6 +741,7 @@ bool TryMatchLoadWord64AndShiftRight(InstructionSelector* selector, Node* node,
case kMode_M2I: case kMode_M2I:
case kMode_M4I: case kMode_M4I:
case kMode_M8I: case kMode_M8I:
case kMode_Root:
UNREACHABLE(); UNREACHABLE();
} }
inputs[input_count++] = ImmediateOperand(ImmediateOperand::INLINE, 4); inputs[input_count++] = ImmediateOperand(ImmediateOperand::INLINE, 4);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment