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

Side by Side Diff: src/compiler/effect-control-linearizer.cc

Issue 1849603002: [turbofan] Effect linearization after representation inference. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Attempt to fix gn Created 4 years, 8 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/effect-control-linearizer.h"
6
7 #include "src/code-factory.h"
8 #include "src/compiler/access-builder.h"
9 #include "src/compiler/js-graph.h"
10 #include "src/compiler/linkage.h"
11 #include "src/compiler/node-properties.h"
12 #include "src/compiler/node.h"
13 #include "src/compiler/schedule.h"
14
15 namespace v8 {
16 namespace internal {
17 namespace compiler {
18
19 EffectControlLinearizer::EffectControlLinearizer(JSGraph* js_graph,
20 Schedule* schedule,
21 Zone* temp_zone)
22 : js_graph_(js_graph), schedule_(schedule), temp_zone_(temp_zone) {}
23
24 Graph* EffectControlLinearizer::graph() const { return js_graph_->graph(); }
25 CommonOperatorBuilder* EffectControlLinearizer::common() const {
26 return js_graph_->common();
27 }
28 SimplifiedOperatorBuilder* EffectControlLinearizer::simplified() const {
29 return js_graph_->simplified();
30 }
31 MachineOperatorBuilder* EffectControlLinearizer::machine() const {
32 return js_graph_->machine();
33 }
34
35 namespace {
36
37 struct BlockEffectData {
38 Node* current_effect = nullptr; // New effect.
39 };
40
41 // Effect phis that need to be updated after the first pass.
42 struct PendingEffectPhi {
43 Node* effect_phi;
44 BasicBlock* block;
45
46 PendingEffectPhi(Node* effect_phi, BasicBlock* block)
47 : effect_phi(effect_phi), block(block) {}
48 };
49
50 void UpdateEffectPhi(Node* node, BasicBlock* block,
51 ZoneVector<BlockEffectData>* block_effects) {
52 // Update all inputs to an effect phi with the effects from the given
53 // block->effect map.
54 DCHECK_EQ(IrOpcode::kEffectPhi, node->opcode());
55 DCHECK_EQ(node->op()->EffectInputCount(), block->PredecessorCount());
56 for (int i = 0; i < node->op()->EffectInputCount(); i++) {
57 Node* input = node->InputAt(i);
58 BasicBlock* predecessor = block->PredecessorAt(static_cast<size_t>(i));
59 Node* input_effect =
60 (*block_effects)[predecessor->rpo_number()].current_effect;
61 if (input != input_effect) {
62 node->ReplaceInput(i, input_effect);
63 }
64 }
65 }
66
67 bool HasIncomingBackEdges(BasicBlock* block) {
68 for (BasicBlock* pred : block->predecessors()) {
69 if (pred->rpo_number() >= block->rpo_number()) {
70 return true;
71 }
72 }
73 return false;
74 }
75
76 void RemoveRegionNode(Node* node) {
77 DCHECK(IrOpcode::kFinishRegion == node->opcode() ||
78 IrOpcode::kBeginRegion == node->opcode());
79 // Update the value/context uses to the value input of the finish node and
80 // the effect uses to the effect input.
81 for (Edge edge : node->use_edges()) {
82 DCHECK(!edge.from()->IsDead());
83 if (NodeProperties::IsEffectEdge(edge)) {
84 edge.UpdateTo(NodeProperties::GetEffectInput(node));
85 } else {
86 DCHECK(!NodeProperties::IsControlEdge(edge));
87 DCHECK(!NodeProperties::IsFrameStateEdge(edge));
88 edge.UpdateTo(node->InputAt(0));
89 }
90 }
91 node->Kill();
92 }
93
94 } // namespace
95
96 void EffectControlLinearizer::Run() {
97 ZoneVector<BlockEffectData> block_effects(temp_zone());
98 ZoneVector<PendingEffectPhi> pending_effect_phis(temp_zone());
99 block_effects.resize(schedule()->RpoBlockCount());
100 NodeVector inputs_buffer(temp_zone());
101
102 for (BasicBlock* block : *(schedule()->rpo_order())) {
103 size_t instr = 0;
104
105 // The control node should be the first.
Benedikt Meurer 2016/04/18 04:34:18 DCHECK this assumption.
Jarin 2016/04/18 07:53:33 Done.
106 Node* control = block->NodeAt(instr);
107 instr++;
108
109 // Iterate over the phis and update the effect phis.
110 Node* effect = nullptr;
111 Node* terminate = nullptr;
112 for (; instr < block->NodeCount(); instr++) {
113 Node* node = block->NodeAt(instr);
114 // Only go through the phis and effect phis.
115 if (node->opcode() == IrOpcode::kEffectPhi) {
116 // There should be at most one effect phi in a block.
117 DCHECK_NULL(effect);
118 // IfException blocks should not have effect phis.
119 DCHECK_NE(IrOpcode::kIfException, control->opcode());
120 effect = node;
121
122 // Make sure we update the inputs to the incoming blocks' effects.
123 if (HasIncomingBackEdges(block)) {
124 // In case of loops, we do not update the effect phi immediately
125 // because the back predecessor has not been handled yet. We just
126 // record the effect phi for later processing.
127 pending_effect_phis.push_back(PendingEffectPhi(node, block));
128 } else {
129 UpdateEffectPhi(node, block, &block_effects);
130 }
131 } else if (node->opcode() == IrOpcode::kPhi) {
132 // Just skip phis.
133 } else if (node->opcode() == IrOpcode::kTerminate) {
134 DCHECK(terminate == nullptr);
135 terminate = node;
136 } else {
137 break;
138 }
139 }
140
141 if (effect == nullptr) {
142 // There was no effect phi.
143 DCHECK(!HasIncomingBackEdges(block));
144 if (block == schedule()->start()) {
145 // Start block => effect is start.
146 DCHECK_EQ(graph()->start(), control);
147 effect = graph()->start();
148 } else if (control->opcode() == IrOpcode::kEnd) {
149 // End block is a just dummy, no effect needed.
Benedikt Meurer 2016/04/18 04:34:18 a just dummy -> just a dummy
Jarin 2016/04/18 07:53:33 Done.
150 DCHECK_EQ(BasicBlock::kNone, block->control());
151 DCHECK_EQ(1, block->size());
Benedikt Meurer 2016/04/18 04:34:18 DCHECK_EQ(1u, block->size())
Jarin 2016/04/18 07:53:33 Done.
152 effect = nullptr;
153 } else {
154 // If all the predecessors have the same effect, we can use it
155 // as our current effect.
156 int rpo_number = block->PredecessorAt(0)->rpo_number();
157 effect = block_effects[rpo_number].current_effect;
158 for (size_t i = 1; i < block->PredecessorCount(); i++) {
159 int rpo_number = block->PredecessorAt(i)->rpo_number();
160 if (block_effects[rpo_number].current_effect != effect) {
161 effect = nullptr;
162 break;
163 }
164 }
165 if (effect == nullptr) {
166 DCHECK_NE(IrOpcode::kIfException, control->opcode());
167 // The input blocks do not have the same effect. We have
168 // to create an effect phi node.
169 inputs_buffer.clear();
170 inputs_buffer.resize(block->PredecessorCount(), graph()->start());
171 inputs_buffer.push_back(control);
172 effect = graph()->NewNode(
173 common()->EffectPhi(static_cast<int>(block->PredecessorCount())),
174 static_cast<int>(inputs_buffer.size()), &(inputs_buffer.front()));
175 // Let us update the effect phi node later.
176 pending_effect_phis.push_back(PendingEffectPhi(effect, block));
177 } else if (control->opcode() == IrOpcode::kIfException) {
178 // The IfException is connected into the effect chain, so we need
179 // to process it here.
180 ProcessNode(control, &effect, &control);
181 }
182 }
183 }
184
185 // Fixup the Terminate node.
186 if (terminate != nullptr) {
187 NodeProperties::ReplaceEffectInput(terminate, effect);
188 }
189
190 // Process the ordinary instructions.
191 for (; instr < block->NodeCount(); instr++) {
192 Node* node = block->NodeAt(instr);
193 ProcessNode(node, &effect, &control);
194 }
195
196 switch (block->control()) {
197 case BasicBlock::kGoto:
198 case BasicBlock::kNone:
199 break;
200
201 case BasicBlock::kCall:
202 case BasicBlock::kTailCall:
203 case BasicBlock::kBranch:
204 case BasicBlock::kSwitch:
205 case BasicBlock::kReturn:
206 case BasicBlock::kDeoptimize:
207 case BasicBlock::kThrow:
208 ProcessNode(block->control_input(), &effect, &control);
209 break;
210 }
211
212 // Store the effect for later use.
213 block_effects[block->rpo_number()].current_effect = effect;
214 }
215
216 // Update the incoming edges of the effect phis that could not be processed
217 // during the first pass (because they could have incoming back edges).
218 for (const PendingEffectPhi& pending_effect_phi : pending_effect_phis) {
219 UpdateEffectPhi(pending_effect_phi.effect_phi, pending_effect_phi.block,
220 &block_effects);
221 }
222 }
223
224 void EffectControlLinearizer::ProcessNode(Node* node, Node** effect,
225 Node** control) {
226 // If the node needs to be wired into the effect/control chain, do this
227 // here.
228 if (TryWireInStateEffect(node, effect, control)) {
229 return;
230 }
231
232 // Remove the end markers of 'atomic' allocation region because the
233 // region should be wired-in now.
234 if (node->opcode() == IrOpcode::kFinishRegion ||
235 node->opcode() == IrOpcode::kBeginRegion) {
236 // Update the value uses to the value input of the finish node and
237 // the effect uses to the effect input.
238
239 // TODO(jarin) Enable this once we make sure everything with side effects
240 // is marked as effectful.
241 if (false) {
242 return RemoveRegionNode(node);
243 }
244 }
245
246 // If the node takes an effect, replace with the current one.
247 if (node->op()->EffectInputCount() > 0) {
248 DCHECK_EQ(1, node->op()->EffectInputCount());
249 Node* input_effect = NodeProperties::GetEffectInput(node);
250
251 if (input_effect != *effect) {
252 NodeProperties::ReplaceEffectInput(node, *effect);
253 }
254
255 // If the node produces an effect, update our current effect. (However,
256 // ignore new effect chains started with ValueEffect.)
257 if (node->op()->EffectOutputCount() > 0) {
258 DCHECK_EQ(1, node->op()->EffectOutputCount());
259 *effect = node;
260 }
261 } else {
262 // New effect chain is only started with a Start or ValueEffect node.
263 DCHECK(node->op()->EffectOutputCount() == 0 ||
264 node->opcode() == IrOpcode::kStart);
265 }
266 }
267
268 bool EffectControlLinearizer::TryWireInStateEffect(Node* node, Node** effect,
269 Node** control) {
270 ValueEffectControl state(nullptr, nullptr, nullptr);
271 switch (node->opcode()) {
272 case IrOpcode::kChangeInt32ToTagged:
273 state = LowerChangeInt32ToTagged(node, *effect, *control);
274 break;
275 case IrOpcode::kChangeUint32ToTagged:
276 state = LowerChangeUint32ToTagged(node, *effect, *control);
277 break;
278 case IrOpcode::kChangeFloat64ToTagged:
279 state = LowerChangeFloat64ToTagged(node, *effect, *control);
280 break;
281 default:
282 return false;
283 }
284 NodeProperties::ReplaceUses(node, state.value);
285 *effect = state.effect;
286 *control = state.control;
287 return true;
288 }
289
290 EffectControlLinearizer::ValueEffectControl
291 EffectControlLinearizer::LowerChangeFloat64ToTagged(Node* node, Node* effect,
292 Node* control) {
293 Node* value = node->InputAt(0);
294
295 Type* const value_type = NodeProperties::GetType(value);
296 Node* const value32 = graph()->NewNode(
297 machine()->TruncateFloat64ToInt32(TruncationMode::kRoundToZero), value);
298 // TODO(bmeurer): This fast case must be disabled until we kill the asm.js
299 // support in the generic JavaScript pipeline, because LoadBuffer is lying
300 // about its result.
301 // if (value_type->Is(Type::Signed32())) {
302 // return ChangeInt32ToTagged(value32, control);
303 // }
304 Node* check_same = graph()->NewNode(
305 machine()->Float64Equal(), value,
306 graph()->NewNode(machine()->ChangeInt32ToFloat64(), value32));
307 Node* branch_same = graph()->NewNode(common()->Branch(), check_same, control);
308
309 Node* if_smi = graph()->NewNode(common()->IfTrue(), branch_same);
310 Node* vsmi;
311 Node* if_box = graph()->NewNode(common()->IfFalse(), branch_same);
312
313 // We only need to check for -0 if the {value} can potentially contain -0.
314 if (value_type->Maybe(Type::MinusZero())) {
315 Node* check_zero = graph()->NewNode(machine()->Word32Equal(), value32,
316 jsgraph()->Int32Constant(0));
317 Node* branch_zero = graph()->NewNode(common()->Branch(BranchHint::kFalse),
318 check_zero, if_smi);
319
320 Node* if_zero = graph()->NewNode(common()->IfTrue(), branch_zero);
321 Node* if_notzero = graph()->NewNode(common()->IfFalse(), branch_zero);
322
323 // In case of 0, we need to check the high bits for the IEEE -0 pattern.
324 Node* check_negative = graph()->NewNode(
325 machine()->Int32LessThan(),
326 graph()->NewNode(machine()->Float64ExtractHighWord32(), value),
327 jsgraph()->Int32Constant(0));
328 Node* branch_negative = graph()->NewNode(
329 common()->Branch(BranchHint::kFalse), check_negative, if_zero);
330
331 Node* if_negative = graph()->NewNode(common()->IfTrue(), branch_negative);
332 Node* if_notnegative =
333 graph()->NewNode(common()->IfFalse(), branch_negative);
334
335 // We need to create a box for negative 0.
336 if_smi = graph()->NewNode(common()->Merge(2), if_notzero, if_notnegative);
337 if_box = graph()->NewNode(common()->Merge(2), if_box, if_negative);
338 }
339
340 // On 64-bit machines we can just wrap the 32-bit integer in a smi, for 32-bit
341 // machines we need to deal with potential overflow and fallback to boxing.
342 if (machine()->Is64() || value_type->Is(Type::SignedSmall())) {
343 vsmi = ChangeInt32ToSmi(value32);
344 } else {
345 Node* smi_tag =
346 graph()->NewNode(machine()->Int32AddWithOverflow(), value32, value32);
347
348 Node* check_ovf = graph()->NewNode(common()->Projection(1), smi_tag);
349 Node* branch_ovf = graph()->NewNode(common()->Branch(BranchHint::kFalse),
350 check_ovf, if_smi);
351
352 Node* if_ovf = graph()->NewNode(common()->IfTrue(), branch_ovf);
353 if_box = graph()->NewNode(common()->Merge(2), if_ovf, if_box);
354
355 if_smi = graph()->NewNode(common()->IfFalse(), branch_ovf);
356 vsmi = graph()->NewNode(common()->Projection(0), smi_tag);
357 }
358
359 // Allocate the box for the {value}.
360 ValueEffectControl box = AllocateHeapNumberWithValue(value, effect, if_box);
361
362 control = graph()->NewNode(common()->Merge(2), if_smi, box.control);
363 value = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
364 vsmi, box.value, control);
365 effect =
366 graph()->NewNode(common()->EffectPhi(2), effect, box.effect, control);
367 return ValueEffectControl(value, effect, control);
368 }
369
370 EffectControlLinearizer::ValueEffectControl
371 EffectControlLinearizer::LowerChangeInt32ToTagged(Node* node, Node* effect,
372 Node* control) {
373 Node* value = node->InputAt(0);
374
375 if (machine()->Is64() ||
376 NodeProperties::GetType(value)->Is(Type::SignedSmall())) {
377 return ValueEffectControl(ChangeInt32ToSmi(value), effect, control);
378 }
379
380 Node* add = graph()->NewNode(machine()->Int32AddWithOverflow(), value, value);
381
382 Node* ovf = graph()->NewNode(common()->Projection(1), add);
383 Node* branch =
384 graph()->NewNode(common()->Branch(BranchHint::kFalse), ovf, control);
385
386 Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
387 ValueEffectControl alloc =
388 AllocateHeapNumberWithValue(ChangeInt32ToFloat64(value), effect, if_true);
389
390 Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
391 Node* vfalse = graph()->NewNode(common()->Projection(0), add);
392
393 Node* merge = graph()->NewNode(common()->Merge(2), alloc.control, if_false);
394 Node* phi = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
395 alloc.value, vfalse, merge);
396 Node* ephi =
397 graph()->NewNode(common()->EffectPhi(2), alloc.effect, effect, merge);
398
399 return ValueEffectControl(phi, ephi, merge);
400 }
401
402 EffectControlLinearizer::ValueEffectControl
403 EffectControlLinearizer::LowerChangeUint32ToTagged(Node* node, Node* effect,
404 Node* control) {
405 Node* value = node->InputAt(0);
406
407 if (NodeProperties::GetType(value)->Is(Type::UnsignedSmall())) {
408 return ValueEffectControl(ChangeUint32ToSmi(value), effect, control);
409 }
410
411 Node* check = graph()->NewNode(machine()->Uint32LessThanOrEqual(), value,
412 SmiMaxValueConstant());
413 Node* branch =
414 graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
415
416 Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
417 Node* vtrue = ChangeUint32ToSmi(value);
418
419 Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
420 ValueEffectControl alloc = AllocateHeapNumberWithValue(
421 ChangeUint32ToFloat64(value), effect, if_false);
422
423 Node* merge = graph()->NewNode(common()->Merge(2), if_true, alloc.control);
424 Node* phi = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
425 vtrue, alloc.value, merge);
426 Node* ephi =
427 graph()->NewNode(common()->EffectPhi(2), effect, alloc.effect, merge);
428
429 return ValueEffectControl(phi, ephi, merge);
430 }
431
432 EffectControlLinearizer::ValueEffectControl
433 EffectControlLinearizer::AllocateHeapNumberWithValue(Node* value, Node* effect,
434 Node* control) {
435 // The AllocateHeapNumberStub does not use the context, so we can safely pass
436 // in Smi zero here.
437 Callable callable = CodeFactory::AllocateHeapNumber(jsgraph()->isolate());
438 Node* target = jsgraph()->HeapConstant(callable.code());
439 Node* context = jsgraph()->NoContextConstant();
440 if (!allocate_heap_number_operator_.is_set()) {
441 CallDescriptor* descriptor = Linkage::GetStubCallDescriptor(
442 jsgraph()->isolate(), jsgraph()->zone(), callable.descriptor(), 0,
443 CallDescriptor::kNoFlags, Operator::kNoThrow);
444 allocate_heap_number_operator_.set(common()->Call(descriptor));
445 }
446 Node* heap_number = graph()->NewNode(allocate_heap_number_operator_.get(),
447 target, context, effect, control);
448 Node* store = graph()->NewNode(
449 machine()->Store(StoreRepresentation(MachineRepresentation::kFloat64,
450 kNoWriteBarrier)),
451 heap_number, HeapNumberValueIndexConstant(), value, heap_number, control);
452 return ValueEffectControl(heap_number, store, control);
453 }
454
455 Node* EffectControlLinearizer::ChangeInt32ToSmi(Node* value) {
456 if (machine()->Is64()) {
457 value = graph()->NewNode(machine()->ChangeInt32ToInt64(), value);
458 }
459 return graph()->NewNode(machine()->WordShl(), value, SmiShiftBitsConstant());
460 }
461
462 Node* EffectControlLinearizer::ChangeUint32ToSmi(Node* value) {
463 if (machine()->Is64()) {
464 value = graph()->NewNode(machine()->ChangeUint32ToUint64(), value);
465 }
466 return graph()->NewNode(machine()->WordShl(), value, SmiShiftBitsConstant());
467 }
468
469 Node* EffectControlLinearizer::ChangeInt32ToFloat64(Node* value) {
470 return graph()->NewNode(machine()->ChangeInt32ToFloat64(), value);
471 }
472
473 Node* EffectControlLinearizer::ChangeUint32ToFloat64(Node* value) {
474 return graph()->NewNode(machine()->ChangeUint32ToFloat64(), value);
475 }
476
477 Node* EffectControlLinearizer::HeapNumberValueIndexConstant() {
478 return jsgraph()->IntPtrConstant(HeapNumber::kValueOffset - kHeapObjectTag);
479 }
480
481 Node* EffectControlLinearizer::SmiMaxValueConstant() {
482 return jsgraph()->Int32Constant(Smi::kMaxValue);
483 }
484
485 Node* EffectControlLinearizer::SmiShiftBitsConstant() {
486 return jsgraph()->IntPtrConstant(kSmiShiftSize + kSmiTagSize);
487 }
488
489 } // namespace compiler
490 } // namespace internal
491 } // namespace v8
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698