Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(144)

Side by Side Diff: src/compiler/store-store-elimination.cc

Issue 2087483003: [compiler] Introduce a simple store-store elimination, disabled by default. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@p1
Patch Set: Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 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
5 #include "src/compiler/store-store-elimination.h"
6
7 #include "src/compiler/js-graph.h"
8 #include "src/compiler/node-properties.h"
9 #include "src/compiler/simplified-operator.h"
10
11 namespace v8 {
12 namespace internal {
13 namespace compiler {
14
15 // A pretty dumb store-store elimination. When the effect chain contains the
Jarin 2016/06/21 13:28:33 "pretty dumb" --> simple
bgeron 2016/06/21 17:48:58 Much better.. Would be good to keep the codebase f
16 // following sequence,
17 //
18 // - StoreField[[+off_1]](x1, y1)
19 // - StoreField[[+off_2]](x2, y2)
20 // - StoreField[[+off_3]](x3, y3)
21 // ...
22 // - StoreField[[+off_n]](xn, yn)
23 //
24 // where the xes are the objects and the ys are the values to be stored, then
25 // we are going to assume that those stores can only overlap if they have
26 // exactly the same offset. If off_i = off_j and xi=xj and i < j, then we
27 // optimize the i'th StoreField away.
28
29 // This optimization should be initiated on the last StoreField in such a
30 // sequence.
31 //
32 // The algorithm works by walking the effect chain from the last StoreField
33 // upwards. While walking, we maintain a map {nextStore} from offsets to
34 // nodes; initially it is empty. As we walk the effect chain upwards, if
35 // nextStore[off] = n, then next StoreField in the effect chain will have
36 // object input n. For example, for this effect chain
37 //
38 // 71: StoreField(60, 0)
39 // 72: StoreField(65, 8)
40 // 73: StoreField(63, 8)
41 // 74: StoreField(65, 16)
42 // 75: StoreField(62, 8)
43 //
44 // just before we get to 72, we will have nextStore = {8: 63, 16: 65}.
45
46 // Here is the complete process.
47 //
48 // - We are at the end of a sequence of consecutive StoreFields.
49 // - We start out with nextStore = empty.
50 // - We then walk the effect chain upwards to find the next StoreField [1].
51 //
52 // - If the offset is not a key of {nextStore} yet, we put it in.
53
54 // - If the offset is a key of {nextStore}, but nextStore[offset] is a
55 // different node, we overwrite nextStore[offset] with the current node.
56 // - If the offset is a key of {nextStore} and nextStore[offset] equals this
57 // node, we eliminate this StoreField.
58 // - As long as the current effect input points to a node with a single
59 // effect output, and as long as its opcode is StoreField, we keep
60 // traversing upwards.
61 //
62 // [1] We make sure that we only traverse the linear part, that is, the part
63 // where every node has exactly one incoming and one outgoing effect edge.
64 // Also, we only keep walking upwards as long as we keep finding consecutive
65 // StoreFields on the same node.
66
67 StoreStoreElimination::StoreStoreElimination(JSGraph* js_graph, Zone* zone)
68 : jsgraph_(js_graph), zone_(zone) {}
69
70 StoreStoreElimination::~StoreStoreElimination() {}
71
72 // 16 bits was chosen fairly arbitrarily; it seems enough now. 8 bits is too
73 // few.
74 typedef uint16_t Offset;
Jarin 2016/06/21 13:28:32 Please, put the file-local definitions into an ano
bgeron 2016/06/21 17:48:58 Done.
75
76 // To safely cast an offset from a FieldAccess, which has a wider range
77 // (namely int).
78 Offset toOffset(int offset) {
Jarin 2016/06/21 13:28:33 toOffset -> ToOffset (link to style guide: https:
bgeron 2016/06/21 17:48:58 Done.
79 CHECK(0 <= offset && offset < (1 << 8 * sizeof(Offset)));
80 return (Offset)offset;
81 }
82
83 Offset toOffset(const FieldAccess& access) { return toOffset(access.offset); }
84
85 // If node has a single effect use, return that node. If node has no or
86 // multiple effect uses, return nullptr.
87 static Node* SingleEffectUse(Node* node) {
88 Node* last_use = nullptr;
89 for (Edge edge : node->use_edges()) {
90 if (!NodeProperties::IsEffectEdge(edge)) {
91 continue;
92 }
93 if (last_use != nullptr) {
94 // more than one
95 return nullptr;
96 }
97 last_use = edge.from();
98 DCHECK_NOT_NULL(last_use);
99 }
100 return last_use;
101 }
102
103 // Return true if node is the last consecutive StoreField node in a linear
104 // part of the effect chain.
105 static bool IsEndOfStoreFieldChain(Node* node) {
106 Node* next_on_chain = SingleEffectUse(node);
107 return (next_on_chain == nullptr ||
108 next_on_chain->op()->opcode() != IrOpcode::kStoreField);
109 }
110
111 // The argument must be a StoreField node. If there is a node before it in the
112 // effect chain, and if this part of the effect chain is linear (no other
113 // effect uses of that previous node), then return that previous node.
114 // Otherwise, return nullptr.
115 //
116 // The returned node need not be a StoreField.
117 Node* PreviousEffectBeforeStoreField(Node* node) {
118 DCHECK_EQ(node->op()->opcode(), IrOpcode::kStoreField);
119 DCHECK_EQ(node->op()->EffectInputCount(), 1);
120
121 Node* previous = NodeProperties::GetEffectInput(node);
122 if (previous != nullptr && node == SingleEffectUse(previous)) {
123 return previous;
124 } else {
125 return nullptr;
126 }
127 }
128
129 bool StoreStoreElimination::IsEligibleNode(Node* node) {
130 return (node->op()->opcode() == IrOpcode::kStoreField) &&
131 IsEndOfStoreFieldChain(node);
132 }
133
134 void StoreStoreElimination::ReduceEligibleNode(Node* node) {
135 DCHECK(IsEligibleNode(node));
136
137 if (FLAG_trace_turbo_ssel) {
138 printf("** StoreStoreElimination::ReduceEligibleNode activated: #%d\n",
139 node->id());
140 }
141
142 // Initialize empty nextStore.
143 ZoneMap<Offset, Node*> nextStore = ZoneMap<Offset, Node*>(zone());
144
145 Node* current_node = node;
146
147 while (current_node->op()->opcode() == IrOpcode::kStoreField) {
148 Offset offset = toOffset(OpParameter<FieldAccess>(current_node->op()));
149 Node* object_input = current_node->InputAt(0);
150
151 // Try to insert. If it was present, this will preserve the original value.
Jarin 2016/06/21 13:28:33 You should handle field aliasing in some way. Perh
bgeron 2016/06/21 17:48:58 Is there more information on field aliasing? I cou
bgeron 2016/06/22 18:00:58 Done.
152 auto insert_result = nextStore.insert(std::make_pair(offset, object_input));
153 if (insert_result.second) {
154 // Key was not present. This means that there is no matching StoreField
155 // to this offset in the future, so we cannot optimize current_node away.
156 // However, we will record the current StoreField in nextStore, and
157 // continue ascending up the chain.
158 if (FLAG_trace_turbo_ssel) {
159 printf(
160 " StoreStoreElimination::ReduceEligibleNode: "
161 "#%d[[+%d]] -- key not present\n",
162 current_node->id(), offset);
163 }
164 } else if (insert_result.first->second != object_input) {
165 // Key was present, and the value did not equal object_input. This means
166 // that there is a StoreField to this offset in the future, but the
167 // object instance comes from a different Node. We pessimistically
168 // assume that we cannot optimize current_node away. However, we will
169 // record the current StoreField in nextStore, and continue ascending up
170 // the chain.
Jarin 2016/06/21 13:28:33 Note: Actually, I believe you could have a multima
bgeron 2016/06/21 17:48:58 I think you're right!
171 insert_result.first->second = object_input;
172 if (FLAG_trace_turbo_ssel) {
173 printf(
174 " StoreStoreElimination::ReduceEligibleNode: "
175 "#%d[[+%d]] -- diff object\n",
176 current_node->id(), offset);
177 }
178 } else {
179 // Key was present, and the value equalled object_input. This means that
180 // soon after in the effect chain, we will do a StoreField to the same
181 // object with the same offset, therefore current_node can be optimized
182 // away. We don't need to update nextStore.
183
184 Node* previous = PreviousEffectBeforeStoreField(current_node);
Jarin 2016/06/21 13:28:32 Can't you move this line to the beginning of the l
bgeron 2016/06/21 17:48:58 Great idea, I missed that.
185 Node* previous_effect = NodeProperties::GetEffectInput(current_node);
186
187 NodeProperties::ReplaceUses(current_node, nullptr, previous_effect,
188 nullptr, nullptr);
189 current_node->Kill();
190 if (FLAG_trace_turbo_ssel) {
191 printf(
192 " StoreStoreElimination::ReduceEligibleNode: "
193 "#%d[[+%d]] -- eliminated\n",
194 current_node->id(), offset);
195 }
196
197 // {current_node} is now invalid. If {previous} exists, that is, if the
198 // chain continues above, the next loop iteration will resume there.
199
200 current_node = previous;
201 if (current_node != nullptr) {
202 continue;
203 } else {
204 break;
205 }
206 }
207
208 // We did not eliminate node {current}, but we want to continue walking up
209 // the effect chain.
210
211 current_node = PreviousEffectBeforeStoreField(current_node);
212 if (current_node == nullptr ||
213 current_node->op()->opcode() != IrOpcode::kStoreField) {
214 break;
215 }
216 }
217
218 if (FLAG_trace_turbo_ssel) {
219 printf(
220 " StoreStoreElimination::ReduceEligibleNode: "
221 "stop chain traversal\n");
222 }
223 }
224
225 } // namespace compiler
226 } // namespace internal
227 } // namespace v8
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698