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

Side by Side Diff: src/compiler/loop-peeling.cc

Issue 816053002: [turbofan] First version of loop peeling. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 5 years, 11 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 2015 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/common-operator.h"
6 #include "src/compiler/graph.h"
7 #include "src/compiler/loop-peeling.h"
8 #include "src/compiler/node.h"
9 #include "src/compiler/node-marker.h"
10 #include "src/compiler/node-properties-inl.h"
11 #include "src/zone.h"
12
13 namespace v8 {
14 namespace internal {
15 namespace compiler {
16
17 struct Peeling {
18 // Maps a node to its index in the {pairs} vector.
19 NodeMarker<size_t> node_map;
20 // The vector which contains the mapped nodes.
21 NodeVector* pairs;
22
23 Peeling(Graph* graph, Zone* tmp_zone, size_t max, NodeVector* p)
24 : node_map(graph, max), pairs(p) {}
25
26 Node* map(Node* node) {
27 if (node_map.Get(node) == 0) return node;
28 return pairs->at(node_map.Get(node));
29 }
30
31 void Insert(Node* original, Node* copy) {
32 node_map.Set(original, 1 + pairs->size());
33 pairs->push_back(original);
34 pairs->push_back(copy);
35 }
36
37 void CopyNodes(Graph* graph, Zone* tmp_zone, Node* dead, NodeRange nodes) {
38 NodeVector inputs(tmp_zone);
39 // Copy all the nodes first.
40 for (Node* node : nodes) {
41 inputs.clear();
42 for (Node* input : node->inputs()) inputs.push_back(map(input));
43 Insert(node, graph->NewNode(node->op(), node->InputCount(), &inputs[0]));
44 }
45
46 // Fix remaining inputs of the copies.
47 for (Node* original : nodes) {
48 Node* copy = pairs->at(node_map.Get(original));
49 for (int i = 0; i < copy->InputCount(); i++) {
50 copy->ReplaceInput(i, map(original->InputAt(i)));
51 }
52 }
53 }
54
55 bool Marked(Node* node) { return node_map.Get(node) > 0; }
56 };
57
58
59 class PeeledIterationImpl : public PeeledIteration {
60 public:
61 NodeVector node_pairs_;
62 explicit PeeledIterationImpl(Zone* zone) : node_pairs_(zone) {}
63 };
64
65
66 Node* PeeledIteration::map(Node* node) {
67 // TODO(turbofan): we use a simple linear search, since the peeled iteration
68 // is really only used in testing.
69 PeeledIterationImpl* impl = static_cast<PeeledIterationImpl*>(this);
Benedikt Meurer 2015/01/16 17:55:36 How about avoiding the PeeledIterationImpl and jus
titzer 2015/01/19 09:47:12 Was hoping to hide the implementation for now, sin
70 for (size_t i = 0; i < impl->node_pairs_.size(); i += 2) {
71 if (impl->node_pairs_[i] == node) return impl->node_pairs_[i + 1];
72 }
73 return node;
74 }
75
76
77 PeeledIteration* LoopPeeler::Peel(Graph* graph, CommonOperatorBuilder* common,
78 LoopTree* loop_tree, LoopTree::Loop* loop,
79 Zone* tmp_zone) {
80 PeeledIterationImpl* iter = new (tmp_zone) PeeledIterationImpl(tmp_zone);
81 Peeling peeling(graph, tmp_zone, loop->TotalSize() * 2 + 2,
82 &iter->node_pairs_);
83
84 //============================================================================
85 // Construct the peeled iteration.
86 //============================================================================
87 Node* dead = graph->NewNode(common->Dead());
88
89 // Map the loop header nodes to their entry values.
90 for (Node* node : loop_tree->HeaderNodes(loop)) {
91 // TODO(titzer): assuming loop entry at index 0.
92 peeling.Insert(node, node->InputAt(0));
93 }
94
95 // Copy all the nodes of loop body for the peeled iteration.
96 peeling.CopyNodes(graph, tmp_zone, dead, loop_tree->BodyNodes(loop));
97
98 //============================================================================
99 // Replace the entry to the loop with the output of the peeled iteration.
100 //============================================================================
101 Node* loop_node = loop_tree->GetLoopControl(loop);
102 Node* new_entry;
103 int backedges = loop_node->InputCount() - 1;
104 if (backedges > 1) {
105 // Multiple backedges from original loop, therefore multiple output edges
106 // from the peeled iteration.
107 NodeVector inputs(tmp_zone);
108 for (int i = 1; i < loop_node->InputCount(); i++) {
109 inputs.push_back(peeling.map(loop_node->InputAt(i)));
110 }
111 Node* merge =
112 graph->NewNode(common->Merge(backedges), backedges, &inputs[0]);
113
114 // Merge values from the multiple output edges of the peeled iteration.
115 for (Node* node : loop_tree->HeaderNodes(loop)) {
116 if (node->opcode() == IrOpcode::kLoop) continue; // already done.
117 inputs.clear();
118 for (int i = 0; i < backedges; i++) {
119 inputs.push_back(peeling.map(node->InputAt(1 + i)));
120 }
121 for (Node* input : inputs) {
122 if (input != inputs[0]) { // Non-redundant phi.
123 inputs.push_back(merge);
124 const Operator* op = common->ResizeMergeOrPhi(node->op(), backedges);
125 Node* phi = graph->NewNode(op, backedges + 1, &inputs[0]);
126 node->ReplaceInput(0, phi);
127 break;
128 }
129 }
130 }
131 new_entry = merge;
132 } else {
133 // Only one backedge, simply replace the input to loop with output of
134 // peeling.
135 for (Node* node : loop_tree->HeaderNodes(loop)) {
136 node->ReplaceInput(0, peeling.map(node->InputAt(0)));
137 }
138 new_entry = peeling.map(loop_node->InputAt(1));
139 }
140 loop_node->ReplaceInput(0, new_entry);
141
142 //============================================================================
143 // Find the loop exit region.
144 //============================================================================
145 NodeVector exits(tmp_zone);
146 Node* end = NULL;
147 for (Node* node : loop_tree->LoopNodes(loop)) {
148 for (Node* use : node->uses()) {
149 if (!loop_tree->Contains(loop, use)) {
150 if (node->opcode() == IrOpcode::kBranch &&
151 (use->opcode() == IrOpcode::kIfTrue ||
152 use->opcode() == IrOpcode::kIfFalse)) {
153 // This is a branch from inside the loop to outside the loop.
154 exits.push_back(use);
155 }
156 }
157 }
158 }
159
160 if (exits.size() == 0) return iter; // no exits => NTL
161
162 if (exits.size() == 1) {
163 // Only one exit, so {end} is that exit.
164 end = exits[0];
165 } else {
166 // {end} should be the common merge from the exits.
167 NodeVector rets(tmp_zone);
168 for (Node* exit : exits) {
169 Node* found = NULL;
170 for (Node* use : exit->uses()) {
171 if (use->opcode() == IrOpcode::kMerge) {
172 found = use;
173 if (end == NULL) {
174 end = found;
175 } else {
176 CHECK_EQ(end, found); // it should be unique!
177 }
178 } else if (use->opcode() == IrOpcode::kReturn) {
179 found = use;
180 rets.push_back(found);
181 }
182 }
183 // There should be a merge or a return for each exit.
184 CHECK_NE(NULL, found);
185 }
186 // Return nodes, the end merge, and the phis associated with the end merge
187 // must be duplicated as well.
188 for (Node* node : rets) exits.push_back(node);
189 if (end != NULL) {
190 exits.push_back(end);
191 for (Node* use : end->uses()) {
192 if (IrOpcode::IsPhiOpcode(use->opcode())) exits.push_back(use);
193 }
194 }
195 }
196
197 //============================================================================
198 // Duplicate the loop exit region and add a merge.
199 //============================================================================
200 NodeRange exit_range(&exits[0], &exits[0] + exits.size());
201 peeling.CopyNodes(graph, tmp_zone, dead, exit_range);
202
203 Node* merge = graph->NewNode(common->Merge(2), end, peeling.map(end));
204 end->ReplaceUses(merge);
205 merge->ReplaceInput(0, end); // HULK SMASH!!
206
207 // Find and update all the edges into either the loop or exit region.
208 for (int i = 0; i < 2; i++) {
209 NodeRange range = i == 0 ? loop_tree->LoopNodes(loop) : exit_range;
210 ZoneVector<Edge> value_edges(tmp_zone);
211 ZoneVector<Edge> effect_edges(tmp_zone);
212
213 for (Node* node : range) {
214 // Gather value and effect edges from outside the region.
215 for (Edge edge : node->use_edges()) {
216 if (!peeling.Marked(edge.from())) {
217 // Edge from outside the loop into the region.
218 if (NodeProperties::IsValueEdge(edge) ||
219 NodeProperties::IsContextEdge(edge)) {
220 value_edges.push_back(edge);
221 } else if (NodeProperties::IsEffectEdge(edge)) {
222 effect_edges.push_back(edge);
223 } else {
224 // don't do anything for control edges.
225 // TODO(titzer): should update control edges to peeled?
226 }
227 }
228 }
229
230 // Update all the value and effect edges at once.
231 if (!value_edges.empty()) {
232 // TODO(titzer): machine type is wrong here.
233 Node* phi = graph->NewNode(common->Phi(kMachAnyTagged, 2), node,
234 peeling.map(node), merge);
235 for (Edge edge : value_edges) edge.UpdateTo(phi);
236 value_edges.clear();
237 }
238 if (!effect_edges.empty()) {
239 Node* effect_phi = graph->NewNode(common->EffectPhi(2), node,
240 peeling.map(node), merge);
241 for (Edge edge : effect_edges) edge.UpdateTo(effect_phi);
242 effect_edges.clear();
243 }
244 }
245 }
246
247 return iter;
248 }
249
250 } // namespace compiler
251 } // namespace internal
252 } // namespace v8
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698