Commit ecc0bc8f authored by Tobias Tebbi's avatar Tobias Tebbi Committed by V8 LUCI CQ

[turboshaft] add basic optimization phase: liveness analysis

Bug: v8:12783
Change-Id: I15cf16bd66a97c33170ca4f1f5e3acc6ff9bf956
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3576129
Auto-Submit: Tobias Tebbi <tebbi@chromium.org>
Commit-Queue: Tobias Tebbi <tebbi@chromium.org>
Reviewed-by: 's avatarNico Hartmann <nicohartmann@chromium.org>
Cr-Commit-Position: refs/heads/main@{#80618}
parent de877f74
......@@ -2828,6 +2828,8 @@ filegroup(
"src/compiler/turboshaft/graph.h",
"src/compiler/turboshaft/operations.cc",
"src/compiler/turboshaft/operations.h",
"src/compiler/turboshaft/optimization-phase.cc",
"src/compiler/turboshaft/optimization-phase.h",
"src/compiler/turboshaft/recreate-schedule.cc",
"src/compiler/turboshaft/recreate-schedule.h",
"src/compiler/type-cache.cc",
......
......@@ -2905,6 +2905,7 @@ v8_header_set("v8_internal_headers") {
"src/compiler/turboshaft/graph-builder.h",
"src/compiler/turboshaft/graph.h",
"src/compiler/turboshaft/operations.h",
"src/compiler/turboshaft/optimization-phase.h",
"src/compiler/turboshaft/recreate-schedule.h",
"src/compiler/type-cache.h",
"src/compiler/type-narrowing-reducer.h",
......@@ -4106,6 +4107,7 @@ v8_source_set("v8_turboshaft") {
"src/compiler/turboshaft/graph-builder.cc",
"src/compiler/turboshaft/graph.cc",
"src/compiler/turboshaft/operations.cc",
"src/compiler/turboshaft/optimization-phase.cc",
"src/compiler/turboshaft/recreate-schedule.cc",
]
......
......@@ -78,6 +78,7 @@
#include "src/compiler/turboshaft/assembler.h"
#include "src/compiler/turboshaft/graph-builder.h"
#include "src/compiler/turboshaft/graph.h"
#include "src/compiler/turboshaft/optimization-phase.h"
#include "src/compiler/turboshaft/recreate-schedule.h"
#include "src/compiler/type-narrowing-reducer.h"
#include "src/compiler/typed-optimization.h"
......@@ -2011,7 +2012,7 @@ struct BranchConditionDuplicationPhase {
};
struct BuildTurboshaftPhase {
DECL_PIPELINE_PHASE_CONSTANTS(BuildTurboShaft)
DECL_PIPELINE_PHASE_CONSTANTS(BuildTurboshaft)
void Run(PipelineData* data, Zone* temp_zone) {
turboshaft::BuildGraph(data->schedule(), data->graph_zone(), temp_zone,
......@@ -2020,6 +2021,16 @@ struct BuildTurboshaftPhase {
}
};
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);
}
};
struct TurboshaftRecreateSchedulePhase {
DECL_PIPELINE_PHASE_CONSTANTS(TurboshaftRecreateSchedule)
......@@ -2860,10 +2871,12 @@ bool PipelineImpl::OptimizeGraph(Linkage* linkage) {
AllowHandleDereference allow_deref;
CodeTracer::StreamScope tracing_scope(data->GetCodeTracer());
tracing_scope.stream()
<< "\n-- TurboShaft Graph ----------------------------\n"
<< "\n-- Turboshaft Graph ----------------------------\n"
<< data->turboshaft_graph();
}
Run<OptimizeTurboshaftPhase>();
Run<TurboshaftRecreateSchedulePhase>(linkage);
if (data->info()->trace_turbo_graph() || FLAG_trace_turbo_scheduler) {
UnparkedScopeIfNeeded scope(data->broker());
......
......@@ -170,7 +170,8 @@ void GraphBuilder::Run() {
DCHECK_EQ(block->SuccessorCount(), 1);
Block* destination = Map(block->SuccessorAt(0));
assembler.Goto(destination);
if (destination->IsLoop()) {
if (destination->IsBound()) {
DCHECK(destination->IsLoop());
FixLoopPhis(destination, target_block);
}
break;
......
......@@ -22,7 +22,7 @@ namespace v8::internal::compiler::turboshaft {
class Assembler;
class VarAssembler;
// `OperationBuffer` is a growable, Zone-allocated buffer to store TurboShaft
// `OperationBuffer` is a growable, Zone-allocated buffer to store Turboshaft
// operations. It is part of a `Graph`.
// The buffer can be seen as an array of 8-byte `OperationStorageSlot` values.
// The structure is append-only, that is, we only add operations at the end.
......@@ -220,8 +220,19 @@ class Block {
return result;
}
Block* LastPredecessor() const { return last_predecessor_; }
Block* NeighboringPredecessor() const { return neighboring_predecessor_; }
bool HasPredecessors() const { return last_predecessor_ != nullptr; }
// The block from the previous graph which produced the current block. This is
// used for translating phi nodes from the previous graph.
void SetOrigin(const Block* origin) {
DCHECK_NULL(origin_);
DCHECK_NE(origin->graph_, graph_);
origin_ = origin;
}
const Block* Origin() const { return origin_; }
OpIndex begin() const {
DCHECK(begin_.valid());
return begin_;
......@@ -243,6 +254,7 @@ class Block {
BlockIndex index_ = BlockIndex::Invalid();
Block* last_predecessor_ = nullptr;
Block* neighboring_predecessor_ = nullptr;
const Block* origin_ = nullptr;
#ifdef DEBUG
Graph* graph_ = nullptr;
#endif
......@@ -342,7 +354,7 @@ class Graph {
return result;
}
bool Add(Block* block) {
V8_INLINE bool Add(Block* block) {
DCHECK_EQ(block->graph_, this);
if (!bound_blocks_.empty() && !block->HasPredecessors()) return false;
bool deferred = true;
......@@ -435,12 +447,16 @@ class Graph {
base::iterator_range<ConstOperationIterator> operations(OpIndex begin,
OpIndex end) const {
DCHECK(begin.valid());
DCHECK(end.valid());
return {ConstOperationIterator(begin, this),
ConstOperationIterator(end, this)};
}
base::iterator_range<MutableOperationIterator> operations(OpIndex begin,
OpIndex end) {
DCHECK(begin.valid());
DCHECK(end.valid());
return {MutableOperationIterator(begin, this),
MutableOperationIterator(end, this)};
}
......
......@@ -220,7 +220,7 @@ struct OpProperties {
}
};
// Baseclass for all TurboShaft operations.
// Baseclass for all Turboshaft operations.
// The `alignas(OpIndex)` is necessary because it is followed by an array of
// `OpIndex` inputs.
struct alignas(OpIndex) Operation {
......@@ -308,24 +308,25 @@ struct OperationT : Operation {
static constexpr OpProperties properties() { return Derived::properties; }
Derived& derived_this() { return *static_cast<Derived*>(this); }
const Derived& derived_this() const {
return *static_cast<const Derived*>(this);
}
// Shadow Operation::inputs to exploit static knowledge about object size.
base::Vector<OpIndex> inputs() {
return {reinterpret_cast<OpIndex*>(reinterpret_cast<char*>(this) +
sizeof(Derived)),
input_count};
derived_this().input_count};
}
base::Vector<const OpIndex> inputs() const {
return {reinterpret_cast<const OpIndex*>(
reinterpret_cast<const char*>(this) + sizeof(Derived)),
input_count};
derived_this().input_count};
}
V8_INLINE OpIndex& input(size_t i) {
return static_cast<Derived*>(this)->inputs()[i];
}
V8_INLINE OpIndex input(size_t i) const {
return static_cast<const Derived*>(this)->inputs()[i];
}
V8_INLINE OpIndex& input(size_t i) { return derived_this().inputs()[i]; }
V8_INLINE OpIndex input(size_t i) const { return derived_this().inputs()[i]; }
static size_t StorageSlotCount(size_t input_count) {
// The operation size in bytes is:
......@@ -373,8 +374,8 @@ struct OperationT : Operation {
bool operator==(const Derived& other) const {
const Derived& derived = *static_cast<const Derived*>(this);
if (derived.inputs() != other.inputs()) return false;
return derived.options() == other.options();
return derived.inputs() == other.inputs() &&
derived.options() == other.options();
}
size_t hash_value() const {
const Derived& derived = *static_cast<const Derived*>(this);
......@@ -382,7 +383,7 @@ struct OperationT : Operation {
}
void PrintOptions(std::ostream& os) const {
const auto& options = static_cast<const Derived*>(this)->options();
const auto& options = derived_this().options();
constexpr size_t options_count =
std::tuple_size<std::remove_reference_t<decltype(options)>>::value;
if (options_count == 0) {
......@@ -411,19 +412,8 @@ struct FixedArityOperationT : OperationT<Derived> {
// Enable concise base access in derived struct.
using Base = FixedArityOperationT;
// Shadow OperationT<Derived>::inputs to exploit static knowledge about input
// count.
// Shadow Operation::input_count to exploit static knowledge.
static constexpr uint16_t input_count = InputCount;
base::Vector<OpIndex> inputs() {
return {reinterpret_cast<OpIndex*>(reinterpret_cast<char*>(this) +
sizeof(Derived)),
InputCount};
}
base::Vector<const OpIndex> inputs() const {
return {reinterpret_cast<const OpIndex*>(
reinterpret_cast<const char*>(this) + sizeof(Derived)),
InputCount};
}
template <class... Args>
explicit FixedArityOperationT(Args... args)
......@@ -434,12 +424,6 @@ struct FixedArityOperationT : OperationT<Derived> {
((inputs[i++] = args), ...);
}
bool operator==(const Derived& other) const {
return std::equal(inputs().begin(), inputs().end(),
other.inputs().begin()) &&
static_cast<const Derived*>(this)->options() == other.options();
}
// Redefine the input initialization to tell C++ about the static input size.
template <class... Args>
static Derived& New(Graph* graph, Args... args) {
......@@ -695,6 +679,8 @@ struct PhiOp : OperationT<PhiOp> {
static constexpr OpProperties properties = OpProperties::Pure();
static constexpr size_t kLoopPhiBackEdgeIndex = 1;
explicit PhiOp(base::Vector<const OpIndex> inputs, MachineRepresentation rep)
: Base(inputs), rep(rep) {}
auto options() const { return std::tuple{rep}; }
......@@ -705,7 +691,7 @@ struct PhiOp : OperationT<PhiOp> {
struct PendingLoopPhiOp : FixedArityOperationT<1, PendingLoopPhiOp> {
MachineRepresentation rep;
union {
// Used when transforming a TurboShaft graph.
// Used when transforming a Turboshaft graph.
// This is not an input because it refers to the old graph.
OpIndex old_backedge_index = OpIndex::Invalid();
// Used when translating from sea-of-nodes.
......@@ -896,6 +882,8 @@ struct ConstantOp : FixedArityOperationT<0, ConstantOp> {
}
}
auto options() const { return std::tuple{kind, storage}; }
void PrintOptions(std::ostream& os) const;
size_t hash_value() const {
switch (kind) {
......@@ -985,7 +973,7 @@ struct IndexedLoadOp : FixedArityOperationT<2, IndexedLoadOp> {
offset(offset) {}
void PrintOptions(std::ostream& os) const;
auto options() const {
return std::tuple{kind, loaded_rep, element_size_log2, offset};
return std::tuple{kind, loaded_rep, offset, element_size_log2};
}
};
......@@ -1047,8 +1035,8 @@ struct IndexedStoreOp : FixedArityOperationT<3, IndexedStoreOp> {
offset(offset) {}
void PrintOptions(std::ostream& os) const;
auto options() const {
return std::tuple{kind, stored_rep, write_barrier, element_size_log2,
offset};
return std::tuple{kind, stored_rep, write_barrier, offset,
element_size_log2};
}
};
......
// Copyright 2022 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/turboshaft/optimization-phase.h"
namespace v8::internal::compiler::turboshaft {
int CountDecimalDigits(uint32_t value) {
int result = 1;
while (value > 9) {
result++;
value = value / 10;
}
return result;
}
std::ostream& operator<<(std::ostream& os, PaddingSpace padding) {
if (padding.spaces > 10000) return os;
for (int i = 0; i < padding.spaces; ++i) {
os << ' ';
}
return os;
}
} // namespace v8::internal::compiler::turboshaft
This diff is collapsed.
......@@ -106,7 +106,7 @@ RecreateScheduleResult ScheduleBuilder::Run() {
DCHECK_GE(input_graph.block_count(), 1);
// The schedule needs to contain an dummy end block because the register
// allocator expects this. This block is not actually reachable with control
// flow. It is added here because the TurboShaft grahp doesn't contain such a
// flow. It is added here because the Turboshaft grahp doesn't contain such a
// block.
blocks.reserve(input_graph.block_count() + 1);
blocks.push_back(current_block);
......
......@@ -966,7 +966,9 @@ DEFINE_FLOAT(script_delay_fraction, 0.0,
"busy wait after each Script::Run by the given fraction of the "
"run's duration")
DEFINE_BOOL(turboshaft, false, "enable TurboFan's TurboShaft phases")
DEFINE_BOOL(turboshaft, false, "enable TurboFan's Turboshaft phases")
DEFINE_BOOL(turboshaft_trace_reduction, false,
"trace individual Turboshaft reduction steps")
// Favor memory over execution speed.
DEFINE_BOOL(optimize_for_size, false,
......
......@@ -369,7 +369,8 @@ class RuntimeCallTimer final {
ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, SimplifiedLowering) \
ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, StoreStoreElimination) \
ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, TraceScheduleAndVerify) \
ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, BuildTurboShaft) \
ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, BuildTurboshaft) \
ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, OptimizeTurboshaft) \
ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, TurboshaftRecreateSchedule) \
ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, TypeAssertions) \
ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, TypedLowering) \
......
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