v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
pretenuring-propagation-reducer.cc
Go to the documentation of this file.
1// Copyright 2023 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
6
8
9namespace {
10
11bool CouldBeAllocate(const Operation& base) {
12 return base.Is<PhiOp>() || base.Is<AllocateOp>();
13}
14
15} // namespace
16
18 OpIndex base_idx = store.base();
19 OpIndex value_idx = store.value();
20 const Operation& base = input_graph_.Get(base_idx);
21 const Operation& value = input_graph_.Get(value_idx);
22
23 if (!CouldBeAllocate(base) || !CouldBeAllocate(value)) {
24 return;
25 }
26
27 if (value.Is<AllocateOp>() &&
29 // {value} is already Old, and we don't care about new-to-old and old-to-old
30 // stores.
31 return;
32 }
33
34 if (value.Is<PhiOp>() && TryFind(value_idx) == nullptr) {
35 // {value} is not worth being recorded, as it's not an Allocation (or a Phi
36 // of Allocations) that could be promoted to Old.
37 return;
38 }
39
40 ZoneVector<OpIndex>* stored_in_base = FindOrCreate(base_idx);
41 stored_in_base->push_back(value_idx);
42}
43
45 // Phis act as storing all of their inputs. It's not how they work in
46 // practice, but if a Phi has a Young input, and is stored in an Old object,
47 // it makes sense to Oldify the phi input.
48
49 // For better performance, we only record inputs that could be an allocation:
50 // Phis with an entry in {store_graph_} or AllocateOp.
51 // Note that this is slightly imprecise for loop Phis (since if the backedge
52 // is a Phi itself, it won't have an entry in {store_graph_} yet), but it
53 // should still be good enough for most cases.
54
55 base::SmallVector<OpIndex, 16> interesting_inputs;
56 for (OpIndex input : phi.inputs()) {
57 const Operation& op = input_graph_.Get(input);
58 if (op.Is<AllocateOp>()) {
59 interesting_inputs.push_back(input);
60 } else if (op.Is<PhiOp>() && TryFind(input) != nullptr) {
61 interesting_inputs.push_back(input);
62 }
63 }
64 if (interesting_inputs.empty()) return;
65
66 ZoneVector<OpIndex>* stored_in_phi = Create(input_graph_.Index(phi));
67 for (OpIndex input : interesting_inputs) {
68 stored_in_phi->push_back(input);
69 }
70}
71
73 const AllocateOp& allocate) {
74 if (allocate.type == AllocationType::kOld) {
75 // We could be a bit more lazy in storing old AllocateOp into {old_allocs_}
76 // (by waiting for a Store or a Phi to use the AllocateOp), but there is
77 // usually very few old allocation, so it makes sense to do it eagerly.
78 old_allocs_.push_back(input_graph_.Index(allocate));
79 }
80}
81
83 // Push into {queue_} all of the values that are "contained" into {base}:
84 // values that are stored to {base} if {base} is an AllocateOp, or Phi inputs
85 // if {base} is a Phi.
86 ZoneVector<OpIndex>* contained = TryFind(base);
87 if (contained == nullptr) return false;
88 for (OpIndex index : *contained) {
89 queue_.push_back(index);
90 }
91 return true;
92}
93
94// Performs a DFS from {old_alloc} and mark everything it finds as Old. The DFS
95// stops on already-Old nodes.
97 queue_.clear();
98 if (!PushContainedValues(old_alloc)) return;
99
100 while (!queue_.empty()) {
101 OpIndex idx = queue_.back();
102 queue_.pop_back();
103 Operation& op = input_graph_.Get(idx);
104 if (AllocateOp* alloc = op.TryCast<AllocateOp>()) {
105 if (alloc->type == AllocationType::kOld) continue;
106 alloc->type = AllocationType::kOld;
108 } else {
109 DCHECK(op.Is<PhiOp>());
110 if (old_phis_.find(idx) != old_phis_.end()) continue;
111 old_phis_.insert(idx);
113 }
114 }
115}
116
118 for (OpIndex old_alloc : old_allocs_) {
119 OldifySubgraph(old_alloc);
120 }
121}
122
124 for (auto& op : input_graph_.AllOperations()) {
125 if (ShouldSkipOperation(op)) {
126 continue;
127 }
128 switch (op.opcode) {
129 case Opcode::kStore:
130 ProcessStore(op.Cast<StoreOp>());
131 break;
132 case Opcode::kAllocate:
133 ProcessAllocate(op.Cast<AllocateOp>());
134 break;
135 case Opcode::kPhi:
136 ProcessPhi(op.Cast<PhiOp>());
137 break;
138 default:
139 break;
140 }
141 }
142}
143
149
150} // namespace v8::internal::compiler::turboshaft
void push_back(const T &value)
base::iterator_range< MutableOperationIterator > AllOperations()
Definition graph.h:937
OpIndex Index(const Operation &op) const
Definition graph.h:655
V8_INLINE const Operation & Get(OpIndex i) const
Definition graph.h:618
V8_EXPORT_PRIVATE V8_INLINE bool ShouldSkipOperation(const Operation &op)
Operation
Definition operation.h:43
#define DCHECK(condition)
Definition logging.h:482
const underlying_operation_t< Op > * TryCast() const
Definition operations.h:990
underlying_operation_t< Op > & Cast()
Definition operations.h:980