Commit ba7d9e5f authored by Darius M's avatar Darius M Committed by V8 LUCI CQ

[turboshaft] port value numbering optimization

Bug: v8:12783
Change-Id: I5b7acf2445b0f898158448dde206a0cecdab6a80
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3764345Reviewed-by: 's avatarTobias Tebbi <tebbi@chromium.org>
Commit-Queue: Darius Mercadier <dmercadier@chromium.org>
Cr-Commit-Position: refs/heads/main@{#82097}
parent 6fbe1bf2
......@@ -2870,6 +2870,7 @@ filegroup(
"src/compiler/turboshaft/recreate-schedule.cc",
"src/compiler/turboshaft/recreate-schedule.h",
"src/compiler/turboshaft/sidetable.h",
"src/compiler/turboshaft/value-numbering-assembler.h",
"src/compiler/type-cache.cc",
"src/compiler/type-cache.h",
"src/compiler/type-narrowing-reducer.cc",
......
......@@ -2985,6 +2985,7 @@ v8_header_set("v8_internal_headers") {
"src/compiler/turboshaft/optimization-phase.h",
"src/compiler/turboshaft/recreate-schedule.h",
"src/compiler/turboshaft/sidetable.h",
"src/compiler/turboshaft/value-numbering-assembler.h",
"src/compiler/type-cache.h",
"src/compiler/type-narrowing-reducer.h",
"src/compiler/typed-optimization.h",
......
......@@ -84,6 +84,7 @@
#include "src/compiler/turboshaft/graph.h"
#include "src/compiler/turboshaft/optimization-phase.h"
#include "src/compiler/turboshaft/recreate-schedule.h"
#include "src/compiler/turboshaft/value-numbering-assembler.h"
#include "src/compiler/type-narrowing-reducer.h"
#include "src/compiler/typed-optimization.h"
#include "src/compiler/typer.h"
......@@ -2045,9 +2046,10 @@ struct OptimizeTurboshaftPhase {
DECL_PIPELINE_PHASE_CONSTANTS(OptimizeTurboshaft)
void Run(PipelineData* data, Zone* temp_zone) {
turboshaft::OptimizationPhase<
turboshaft::LivenessAnalyzer,
turboshaft::Assembler>::Run(&data->turboshaft_graph(), temp_zone);
turboshaft::OptimizationPhase<turboshaft::LivenessAnalyzer,
turboshaft::ValueNumberingAssembler>::
Run(&data->turboshaft_graph(), temp_zone,
turboshaft::VisitOrder::kDominator);
}
};
......
......@@ -208,6 +208,9 @@ class Assembler
public:
Block* NewBlock(Block::Kind kind) { return graph_.NewBlock(kind); }
void EnterBlock(const Block& block) { USE(block); }
void ExitBlock(const Block& block) { USE(block); }
V8_INLINE bool Bind(Block* block) {
if (!graph().Add(block)) return false;
DCHECK_NULL(current_block_);
......
......@@ -231,6 +231,8 @@ class RandomAccessStackDominatorNode
// Returns the lowest common dominator of {this} and {other}.
Derived* GetCommonDominator(RandomAccessStackDominatorNode<Derived>* other);
int Depth() const { return len_; }
private:
friend class Graph;
friend class DominatorForwardTreeNode<Derived>;
......
......@@ -5,6 +5,7 @@
#ifndef V8_COMPILER_TURBOSHAFT_OPERATIONS_H_
#define V8_COMPILER_TURBOSHAFT_OPERATIONS_H_
#include <cmath>
#include <cstdint>
#include <cstring>
#include <limits>
......@@ -200,6 +201,10 @@ struct OpProperties {
!(can_read || can_write || can_abort || is_block_terminator);
const bool is_required_when_unused =
can_write || can_abort || is_block_terminator;
// Nodes that don't read, write and aren't block terminators can be eliminated
// via value numbering.
const bool can_be_eliminated =
!(can_read || can_write || is_block_terminator);
constexpr OpProperties(bool can_read, bool can_write, bool can_abort,
bool is_block_terminator)
......@@ -1031,10 +1036,20 @@ struct ConstantOp : FixedArityOperationT<0, ConstantOp> {
case Kind::kTaggedIndex:
return storage.integral == other.storage.integral;
case Kind::kFloat32:
return storage.float32 == other.storage.float32;
// Using a bit_cast to uint32_t in order to return false when comparing
// +0 and -0.
return base::bit_cast<uint32_t>(storage.float32) ==
base::bit_cast<uint32_t>(other.storage.float32) ||
(std::isnan(storage.float32) &&
std::isnan(other.storage.float32));
case Kind::kFloat64:
case Kind::kNumber:
return storage.float64 == other.storage.float64;
// Using a bit_cast to uint64_t in order to return false when comparing
// +0 and -0.
return base::bit_cast<uint64_t>(storage.float64) ==
base::bit_cast<uint64_t>(other.storage.float64) ||
(std::isnan(storage.float64) &&
std::isnan(other.storage.float64));
case Kind::kExternal:
return storage.external.address() == other.storage.external.address();
case Kind::kHeapObject:
......
......@@ -95,15 +95,16 @@ struct LivenessAnalyzer : AnalyzerBase {
}
};
enum class VisitOrder { kAsEmitted, kDominator };
template <class Analyzer, class Assembler>
class OptimizationPhase {
private:
struct Impl;
public:
enum class VisitOrder { kNatural, kDominator };
static void Run(Graph* input, Zone* phase_zone,
VisitOrder visit_order = VisitOrder::kNatural) {
VisitOrder visit_order = VisitOrder::kAsEmitted) {
Impl phase{*input, phase_zone, visit_order};
if (FLAG_turboshaft_trace_reduction) {
phase.template Run<true>();
......@@ -111,8 +112,9 @@ class OptimizationPhase {
phase.template Run<false>();
}
}
static void RunWithoutTracing(Graph* input, Zone* phase_zone,
VisitOrder visit_order = VisitOrder::kNatural) {
static void RunWithoutTracing(
Graph* input, Zone* phase_zone,
VisitOrder visit_order = VisitOrder::kAsEmitted) {
Impl phase{*input, phase_zone, visit_order};
phase.template Run<false>();
}
......@@ -146,14 +148,14 @@ struct OptimizationPhase<Analyzer, Assembler>::Impl {
if (visit_order == VisitOrder::kDominator) {
RunDominatorOrder<trace_reduction>();
} else {
RunNaturalOrder<trace_reduction>();
RunAsEmittedOrder<trace_reduction>();
}
input_graph.SwapWithCompanion();
}
template <bool trace_reduction>
void RunNaturalOrder() {
void RunAsEmittedOrder() {
for (const Block& input_block : input_graph.blocks()) {
VisitBlock<trace_reduction>(input_block);
}
......@@ -179,12 +181,14 @@ struct OptimizationPhase<Analyzer, Assembler>::Impl {
template <bool trace_reduction>
void VisitBlock(const Block& input_block) {
assembler.EnterBlock(input_block);
current_input_block = &input_block;
if constexpr (trace_reduction) {
std::cout << PrintAsBlockHeader{input_block} << "\n";
}
if (!assembler.Bind(MapToNewGraph(input_block.index()))) {
if constexpr (trace_reduction) TraceBlockUnreachable();
assembler.ExitBlock(input_block);
return;
}
assembler.current_block()->SetDeferred(input_block.IsDeferred());
......@@ -226,6 +230,7 @@ struct OptimizationPhase<Analyzer, Assembler>::Impl {
}
op_mapping[index.id()] = new_index;
}
assembler.ExitBlock(input_block);
if constexpr (trace_reduction) TraceBlockFinished();
}
......@@ -306,7 +311,7 @@ struct OptimizationPhase<Analyzer, Assembler>::Impl {
// need to skip phi inputs that belong to control predecessors that have no
// equivalent in the new graph.
// When iterating the graph in kNatural order (ie, going through all of
// When iterating the graph in kAsEmitted order (ie, going through all of
// the blocks in linear order), we assume that the order of control
// predecessors did not change. In kDominator order, the order of control
// predecessor might or might not change.
......
This diff is collapsed.
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