From 024e5fb4fa169b16ba24af2a3397e05953edefcc Mon Sep 17 00:00:00 2001 From: Hao Xu Date: Tue, 18 Oct 2022 19:42:33 +0800 Subject: [PATCH] [CSA][codegen] Add BitcastElision Phase Turbofan generates bitcast nodes like BitcastWordToTaggedSigned to ensure the value types of definitions and uses are matched. These nodes can be elided after MachineGraphVerifier verifying the graph. This can avoid generating redundant instructions: Before: xorl r15,r15 cmpl [rdx+0xb],r15 After: cmpl [rdx+0xb],0x0 Change-Id: I84bc1b05d77ed9487001e34a93dfe14e45a7a678 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3837161 Commit-Queue: Hao A Xu Reviewed-by: Tobias Tebbi Cr-Commit-Position: refs/heads/main@{#83811} --- BUILD.bazel | 2 + BUILD.gn | 2 + src/compiler/backend/bitcast-elider.cc | 62 ++++++++++++++++++++++++++ src/compiler/backend/bitcast-elider.h | 41 +++++++++++++++++ src/compiler/pipeline.cc | 13 ++++++ src/logging/runtime-call-stats.h | 1 + tools/zone-stats/categories.js | 1 + 7 files changed, 122 insertions(+) create mode 100644 src/compiler/backend/bitcast-elider.cc create mode 100644 src/compiler/backend/bitcast-elider.h 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',