diff --git a/BUILD.bazel b/BUILD.bazel index a1d45e7f86..1e477568e3 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -2664,6 +2664,8 @@ filegroup( "src/compiler/all-nodes.h", "src/compiler/allocation-builder.h", "src/compiler/allocation-builder-inl.h", + "src/compiler/backend/bitcast-elider.cc", + "src/compiler/backend/bitcast-elider.h", "src/compiler/backend/code-generator.cc", "src/compiler/backend/code-generator.h", "src/compiler/backend/code-generator-impl.h", diff --git a/BUILD.gn b/BUILD.gn index 6980123e54..da7941186b 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -2806,6 +2806,7 @@ v8_header_set("v8_internal_headers") { "src/compiler/all-nodes.h", "src/compiler/allocation-builder-inl.h", "src/compiler/allocation-builder.h", + "src/compiler/backend/bitcast-elider.h", "src/compiler/backend/code-generator-impl.h", "src/compiler/backend/code-generator.h", "src/compiler/backend/frame-elider.h", @@ -4045,6 +4046,7 @@ v8_compiler_sources = [ "src/compiler/access-info.cc", "src/compiler/add-type-assertions-reducer.cc", "src/compiler/all-nodes.cc", + "src/compiler/backend/bitcast-elider.cc", "src/compiler/backend/code-generator.cc", "src/compiler/backend/frame-elider.cc", "src/compiler/backend/gap-resolver.cc", diff --git a/src/compiler/backend/bitcast-elider.cc b/src/compiler/backend/bitcast-elider.cc new file mode 100644 index 0000000000..263e3d691b --- /dev/null +++ b/src/compiler/backend/bitcast-elider.cc @@ -0,0 +1,62 @@ +// Copyright 2016 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "src/compiler/backend/bitcast-elider.h" + +#include "src/compiler/graph.h" + +namespace v8 { +namespace internal { +namespace compiler { + +namespace { + +bool IsBitcast(Node* node) { + // We can only elide kBitcastTaggedToWordForTagAndSmiBits and + // kBitcastWordToTaggedSigned because others might affect GC / safepoint + // tables. + return node->opcode() == IrOpcode::kBitcastTaggedToWordForTagAndSmiBits || + node->opcode() == IrOpcode::kBitcastWordToTaggedSigned; +} + +} // namespace + +void BitcastElider::Enqueue(Node* node) { + if (seen_.Get(node)) return; + seen_.Set(node, true); + to_visit_.push(node); +} + +void BitcastElider::VisitNode(Node* node) { + for (int i = 0; i < node->InputCount(); i++) { + Node* input = node->InputAt(i); + bool should_replace_input = false; + while (IsBitcast(input)) { + input = input->InputAt(0); + should_replace_input = true; + } + if (should_replace_input) { + node->ReplaceInput(i, input); + } + Enqueue(input); + } +} + +void BitcastElider::ProcessGraph() { + Enqueue(graph_->end()); + while (!to_visit_.empty()) { + Node* node = to_visit_.front(); + to_visit_.pop(); + VisitNode(node); + } +} + +BitcastElider::BitcastElider(Zone* zone, Graph* graph) + : graph_(graph), to_visit_(zone), seen_(graph, 2) {} + +void BitcastElider::Reduce() { ProcessGraph(); } + +} // namespace compiler +} // namespace internal +} // namespace v8 diff --git a/src/compiler/backend/bitcast-elider.h b/src/compiler/backend/bitcast-elider.h new file mode 100644 index 0000000000..b20d127a98 --- /dev/null +++ b/src/compiler/backend/bitcast-elider.h @@ -0,0 +1,41 @@ +// Copyright 2016 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_COMPILER_BACKEND_BITCAST_ELIDER_H_ +#define V8_COMPILER_BACKEND_BITCAST_ELIDER_H_ + +#include "src/compiler/node-marker.h" +#include "src/compiler/node.h" +#include "src/zone/zone.h" + +namespace v8 { +namespace internal { +namespace compiler { + +class Graph; + +// Elide all the Bitcast nodes which are required by MachineGraphVerifier. This +// avoid generating redundant move instructions in instruction selection phase. +class BitcastElider { + public: + BitcastElider(Zone* zone, Graph* graph); + ~BitcastElider() = default; + + void Reduce(); + + void Enqueue(Node* node); + void VisitNode(Node* node); + void ProcessGraph(); + + private: + Graph* const graph_; + ZoneQueue to_visit_; + NodeMarker seen_; +}; + +} // namespace compiler +} // namespace internal +} // namespace v8 + +#endif // V8_COMPILER_BACKEND_BITCAST_ELIDER_H_ diff --git a/src/compiler/pipeline.cc b/src/compiler/pipeline.cc index a4cf5ca43e..07da84541d 100644 --- a/src/compiler/pipeline.cc +++ b/src/compiler/pipeline.cc @@ -20,6 +20,7 @@ #include "src/common/high-allocation-throughput-scope.h" #include "src/compiler/add-type-assertions-reducer.h" #include "src/compiler/all-nodes.h" +#include "src/compiler/backend/bitcast-elider.h" #include "src/compiler/backend/code-generator.h" #include "src/compiler/backend/frame-elider.h" #include "src/compiler/backend/instruction-selector.h" @@ -2383,6 +2384,14 @@ struct InstructionSelectionPhase { } }; +struct BitcastElisionPhase { + DECL_PIPELINE_PHASE_CONSTANTS(BitcastElision) + + void Run(PipelineData* data, Zone* temp_zone) { + BitcastElider bitcast_optimizer(temp_zone, data->graph()); + bitcast_optimizer.Reduce(); + } +}; struct MeetRegisterConstraintsPhase { DECL_PIPELINE_PHASE_CONSTANTS(MeetRegisterConstraints) @@ -3729,6 +3738,10 @@ bool PipelineImpl::SelectInstructions(Linkage* linkage) { data->debug_name(), &temp_zone); } + if (Builtins::IsBuiltinId(data->info()->builtin())) { + Run(); + } + data->InitializeInstructionSequence(call_descriptor); // Depending on which code path led us to this function, the frame may or diff --git a/src/logging/runtime-call-stats.h b/src/logging/runtime-call-stats.h index 202c379f64..fd51b6b5b0 100644 --- a/src/logging/runtime-call-stats.h +++ b/src/logging/runtime-call-stats.h @@ -323,6 +323,7 @@ class RuntimeCallTimer final { ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, AllocateGeneralRegisters) \ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, AssembleCode) \ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, AssignSpillSlots) \ + ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, BitcastElision) \ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, BranchConditionDuplication) \ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, BuildLiveRangeBundles) \ ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, BuildLiveRanges) \ diff --git a/tools/zone-stats/categories.js b/tools/zone-stats/categories.js index 581a69a01e..82d49cfd6a 100644 --- a/tools/zone-stats/categories.js +++ b/tools/zone-stats/categories.js @@ -48,6 +48,7 @@ export const CATEGORIES = new Map([ 'V8.TFAllocateGeneralRegisters', 'V8.TFAssembleCode', 'V8.TFAssignSpillSlots', + 'V8.TFBitcastElision', 'V8.TFBuildLiveRangeBundles', 'V8.TFBuildLiveRanges', 'V8.TFBytecodeGraphBuilder',