blob: d4ec6bc9438318487c3fa0b60aa0bb4d122c003b [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// Copyright 2014 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
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005#include "src/compiler/common-operator.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006#include "src/compiler/graph.h"
7#include "src/compiler/instruction.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008#include "src/compiler/schedule.h"
9#include "src/compiler/state-values-utils.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010
11namespace v8 {
12namespace internal {
13namespace compiler {
14
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015
16FlagsCondition CommuteFlagsCondition(FlagsCondition condition) {
17 switch (condition) {
18 case kSignedLessThan:
19 return kSignedGreaterThan;
20 case kSignedGreaterThanOrEqual:
21 return kSignedLessThanOrEqual;
22 case kSignedLessThanOrEqual:
23 return kSignedGreaterThanOrEqual;
24 case kSignedGreaterThan:
25 return kSignedLessThan;
26 case kUnsignedLessThan:
27 return kUnsignedGreaterThan;
28 case kUnsignedGreaterThanOrEqual:
29 return kUnsignedLessThanOrEqual;
30 case kUnsignedLessThanOrEqual:
31 return kUnsignedGreaterThanOrEqual;
32 case kUnsignedGreaterThan:
33 return kUnsignedLessThan;
34 case kFloatLessThanOrUnordered:
35 return kFloatGreaterThanOrUnordered;
36 case kFloatGreaterThanOrEqual:
37 return kFloatLessThanOrEqual;
38 case kFloatLessThanOrEqual:
39 return kFloatGreaterThanOrEqual;
40 case kFloatGreaterThanOrUnordered:
41 return kFloatLessThanOrUnordered;
42 case kFloatLessThan:
43 return kFloatGreaterThan;
44 case kFloatGreaterThanOrEqualOrUnordered:
45 return kFloatLessThanOrEqualOrUnordered;
46 case kFloatLessThanOrEqualOrUnordered:
47 return kFloatGreaterThanOrEqualOrUnordered;
48 case kFloatGreaterThan:
49 return kFloatLessThan;
50 case kEqual:
51 case kNotEqual:
52 case kOverflow:
53 case kNotOverflow:
54 case kUnorderedEqual:
55 case kUnorderedNotEqual:
56 return condition;
57 }
58 UNREACHABLE();
59 return condition;
60}
61
62
63void InstructionOperand::Print(const RegisterConfiguration* config) const {
64 OFStream os(stdout);
65 PrintableInstructionOperand wrapper;
66 wrapper.register_configuration_ = config;
67 wrapper.op_ = *this;
68 os << wrapper << std::endl;
69}
70
71
72void InstructionOperand::Print() const {
73 const RegisterConfiguration* config =
74 RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN);
75 Print(config);
76}
77
78
Emily Bernierd0a1eb72015-03-24 16:35:39 -040079std::ostream& operator<<(std::ostream& os,
80 const PrintableInstructionOperand& printable) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000081 const InstructionOperand& op = printable.op_;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040082 const RegisterConfiguration* conf = printable.register_configuration_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000083 switch (op.kind()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000084 case InstructionOperand::UNALLOCATED: {
85 const UnallocatedOperand* unalloc = UnallocatedOperand::cast(&op);
86 os << "v" << unalloc->virtual_register();
87 if (unalloc->basic_policy() == UnallocatedOperand::FIXED_SLOT) {
88 return os << "(=" << unalloc->fixed_slot_index() << "S)";
89 }
90 switch (unalloc->extended_policy()) {
91 case UnallocatedOperand::NONE:
92 return os;
93 case UnallocatedOperand::FIXED_REGISTER:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000094 return os << "(="
95 << conf->GetGeneralRegisterName(
96 unalloc->fixed_register_index())
97 << ")";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000098 case UnallocatedOperand::FIXED_DOUBLE_REGISTER:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000099 return os << "(="
100 << conf->GetDoubleRegisterName(
101 unalloc->fixed_register_index())
102 << ")";
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000103 case UnallocatedOperand::MUST_HAVE_REGISTER:
104 return os << "(R)";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000105 case UnallocatedOperand::MUST_HAVE_SLOT:
106 return os << "(S)";
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000107 case UnallocatedOperand::SAME_AS_FIRST_INPUT:
108 return os << "(1)";
109 case UnallocatedOperand::ANY:
110 return os << "(-)";
111 }
112 }
113 case InstructionOperand::CONSTANT:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000114 return os << "[constant:" << ConstantOperand::cast(op).virtual_register()
115 << "]";
116 case InstructionOperand::IMMEDIATE: {
117 auto imm = ImmediateOperand::cast(op);
118 switch (imm.type()) {
119 case ImmediateOperand::INLINE:
120 return os << "#" << imm.inline_value();
121 case ImmediateOperand::INDEXED:
122 return os << "[immediate:" << imm.indexed_value() << "]";
123 }
124 }
125 case InstructionOperand::EXPLICIT:
126 case InstructionOperand::ALLOCATED: {
127 auto allocated = LocationOperand::cast(op);
128 if (op.IsStackSlot()) {
129 os << "[stack:" << LocationOperand::cast(op).index();
130 } else if (op.IsDoubleStackSlot()) {
131 os << "[double_stack:" << LocationOperand::cast(op).index();
132 } else if (op.IsRegister()) {
133 os << "[" << LocationOperand::cast(op).GetRegister().ToString() << "|R";
134 } else {
135 DCHECK(op.IsDoubleRegister());
136 os << "[" << LocationOperand::cast(op).GetDoubleRegister().ToString()
137 << "|R";
138 }
139 if (allocated.IsExplicit()) {
140 os << "|E";
141 }
142 switch (allocated.representation()) {
143 case MachineRepresentation::kNone:
144 os << "|-";
145 break;
146 case MachineRepresentation::kBit:
147 os << "|b";
148 break;
149 case MachineRepresentation::kWord8:
150 os << "|w8";
151 break;
152 case MachineRepresentation::kWord16:
153 os << "|w16";
154 break;
155 case MachineRepresentation::kWord32:
156 os << "|w32";
157 break;
158 case MachineRepresentation::kWord64:
159 os << "|w64";
160 break;
161 case MachineRepresentation::kFloat32:
162 os << "|f32";
163 break;
164 case MachineRepresentation::kFloat64:
165 os << "|f64";
166 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100167 case MachineRepresentation::kSimd128:
168 os << "|s128";
169 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000170 case MachineRepresentation::kTagged:
171 os << "|t";
172 break;
173 }
174 return os << "]";
175 }
176 case InstructionOperand::INVALID:
177 return os << "(x)";
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000178 }
179 UNREACHABLE();
180 return os;
181}
182
183
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000184void MoveOperands::Print(const RegisterConfiguration* config) const {
185 OFStream os(stdout);
186 PrintableInstructionOperand wrapper;
187 wrapper.register_configuration_ = config;
188 wrapper.op_ = destination();
189 os << wrapper << " = ";
190 wrapper.op_ = source();
191 os << wrapper << std::endl;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000192}
193
194
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000195void MoveOperands::Print() const {
196 const RegisterConfiguration* config =
197 RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN);
198 Print(config);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000199}
200
201
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400202std::ostream& operator<<(std::ostream& os,
203 const PrintableMoveOperands& printable) {
204 const MoveOperands& mo = *printable.move_operands_;
205 PrintableInstructionOperand printable_op = {printable.register_configuration_,
206 mo.destination()};
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400207 os << printable_op;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000208 if (!mo.source().Equals(mo.destination())) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400209 printable_op.op_ = mo.source();
210 os << " = " << printable_op;
211 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000212 return os << ";";
213}
214
215
216bool ParallelMove::IsRedundant() const {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000217 for (auto move : *this) {
218 if (!move->IsRedundant()) return false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000219 }
220 return true;
221}
222
223
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000224MoveOperands* ParallelMove::PrepareInsertAfter(MoveOperands* move) const {
225 MoveOperands* replacement = nullptr;
226 MoveOperands* to_eliminate = nullptr;
227 for (auto curr : *this) {
228 if (curr->IsEliminated()) continue;
229 if (curr->destination().EqualsCanonicalized(move->source())) {
230 DCHECK(!replacement);
231 replacement = curr;
232 if (to_eliminate != nullptr) break;
233 } else if (curr->destination().EqualsCanonicalized(move->destination())) {
234 DCHECK(!to_eliminate);
235 to_eliminate = curr;
236 if (replacement != nullptr) break;
237 }
238 }
239 DCHECK_IMPLIES(replacement == to_eliminate, replacement == nullptr);
240 if (replacement != nullptr) move->set_source(replacement->source());
241 return to_eliminate;
242}
243
244
245ExplicitOperand::ExplicitOperand(LocationKind kind, MachineRepresentation rep,
246 int index)
247 : LocationOperand(EXPLICIT, kind, rep, index) {
248 DCHECK_IMPLIES(kind == REGISTER && !IsFloatingPoint(rep),
249 Register::from_code(index).IsAllocatable());
250 DCHECK_IMPLIES(kind == REGISTER && IsFloatingPoint(rep),
251 DoubleRegister::from_code(index).IsAllocatable());
252}
253
254
255Instruction::Instruction(InstructionCode opcode)
256 : opcode_(opcode),
257 bit_field_(OutputCountField::encode(0) | InputCountField::encode(0) |
258 TempCountField::encode(0) | IsCallField::encode(false)),
259 reference_map_(nullptr) {
260 parallel_moves_[0] = nullptr;
261 parallel_moves_[1] = nullptr;
262}
263
264
265Instruction::Instruction(InstructionCode opcode, size_t output_count,
266 InstructionOperand* outputs, size_t input_count,
267 InstructionOperand* inputs, size_t temp_count,
268 InstructionOperand* temps)
269 : opcode_(opcode),
270 bit_field_(OutputCountField::encode(output_count) |
271 InputCountField::encode(input_count) |
272 TempCountField::encode(temp_count) |
273 IsCallField::encode(false)),
274 reference_map_(nullptr) {
275 parallel_moves_[0] = nullptr;
276 parallel_moves_[1] = nullptr;
277 size_t offset = 0;
278 for (size_t i = 0; i < output_count; ++i) {
279 DCHECK(!outputs[i].IsInvalid());
280 operands_[offset++] = outputs[i];
281 }
282 for (size_t i = 0; i < input_count; ++i) {
283 DCHECK(!inputs[i].IsInvalid());
284 operands_[offset++] = inputs[i];
285 }
286 for (size_t i = 0; i < temp_count; ++i) {
287 DCHECK(!temps[i].IsInvalid());
288 operands_[offset++] = temps[i];
289 }
290}
291
292
293bool Instruction::AreMovesRedundant() const {
294 for (int i = Instruction::FIRST_GAP_POSITION;
295 i <= Instruction::LAST_GAP_POSITION; i++) {
296 if (parallel_moves_[i] != nullptr && !parallel_moves_[i]->IsRedundant()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400297 return false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000298 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400299 }
300 return true;
301}
302
303
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000304void Instruction::Print(const RegisterConfiguration* config) const {
305 OFStream os(stdout);
306 PrintableInstruction wrapper;
307 wrapper.instr_ = this;
308 wrapper.register_configuration_ = config;
309 os << wrapper << std::endl;
310}
311
312
313void Instruction::Print() const {
314 const RegisterConfiguration* config =
315 RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN);
316 Print(config);
317}
318
319
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400320std::ostream& operator<<(std::ostream& os,
321 const PrintableParallelMove& printable) {
322 const ParallelMove& pm = *printable.parallel_move_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000323 bool first = true;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000324 for (auto move : pm) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000325 if (move->IsEliminated()) continue;
326 if (!first) os << " ";
327 first = false;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400328 PrintableMoveOperands pmo = {printable.register_configuration_, move};
329 os << pmo;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000330 }
331 return os;
332}
333
334
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000335void ReferenceMap::RecordReference(const AllocatedOperand& op) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000336 // Do not record arguments as pointers.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000337 if (op.IsStackSlot() && LocationOperand::cast(op).index() < 0) return;
338 DCHECK(!op.IsDoubleRegister() && !op.IsDoubleStackSlot());
339 reference_operands_.push_back(op);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000340}
341
342
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000343std::ostream& operator<<(std::ostream& os, const ReferenceMap& pm) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000344 os << "{";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000345 bool first = true;
346 PrintableInstructionOperand poi = {
347 RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN),
348 InstructionOperand()};
349 for (auto& op : pm.reference_operands_) {
350 if (!first) {
351 os << ";";
352 } else {
353 first = false;
354 }
355 poi.op_ = op;
356 os << poi;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000357 }
358 return os << "}";
359}
360
361
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400362std::ostream& operator<<(std::ostream& os, const ArchOpcode& ao) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000363 switch (ao) {
364#define CASE(Name) \
365 case k##Name: \
366 return os << #Name;
367 ARCH_OPCODE_LIST(CASE)
368#undef CASE
369 }
370 UNREACHABLE();
371 return os;
372}
373
374
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400375std::ostream& operator<<(std::ostream& os, const AddressingMode& am) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000376 switch (am) {
377 case kMode_None:
378 return os;
379#define CASE(Name) \
380 case kMode_##Name: \
381 return os << #Name;
382 TARGET_ADDRESSING_MODE_LIST(CASE)
383#undef CASE
384 }
385 UNREACHABLE();
386 return os;
387}
388
389
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400390std::ostream& operator<<(std::ostream& os, const FlagsMode& fm) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000391 switch (fm) {
392 case kFlags_none:
393 return os;
394 case kFlags_branch:
395 return os << "branch";
396 case kFlags_set:
397 return os << "set";
398 }
399 UNREACHABLE();
400 return os;
401}
402
403
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400404std::ostream& operator<<(std::ostream& os, const FlagsCondition& fc) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000405 switch (fc) {
406 case kEqual:
407 return os << "equal";
408 case kNotEqual:
409 return os << "not equal";
410 case kSignedLessThan:
411 return os << "signed less than";
412 case kSignedGreaterThanOrEqual:
413 return os << "signed greater than or equal";
414 case kSignedLessThanOrEqual:
415 return os << "signed less than or equal";
416 case kSignedGreaterThan:
417 return os << "signed greater than";
418 case kUnsignedLessThan:
419 return os << "unsigned less than";
420 case kUnsignedGreaterThanOrEqual:
421 return os << "unsigned greater than or equal";
422 case kUnsignedLessThanOrEqual:
423 return os << "unsigned less than or equal";
424 case kUnsignedGreaterThan:
425 return os << "unsigned greater than";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000426 case kFloatLessThanOrUnordered:
427 return os << "less than or unordered (FP)";
428 case kFloatGreaterThanOrEqual:
429 return os << "greater than or equal (FP)";
430 case kFloatLessThanOrEqual:
431 return os << "less than or equal (FP)";
432 case kFloatGreaterThanOrUnordered:
433 return os << "greater than or unordered (FP)";
434 case kFloatLessThan:
435 return os << "less than (FP)";
436 case kFloatGreaterThanOrEqualOrUnordered:
437 return os << "greater than, equal or unordered (FP)";
438 case kFloatLessThanOrEqualOrUnordered:
439 return os << "less than, equal or unordered (FP)";
440 case kFloatGreaterThan:
441 return os << "greater than (FP)";
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000442 case kUnorderedEqual:
443 return os << "unordered equal";
444 case kUnorderedNotEqual:
445 return os << "unordered not equal";
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000446 case kOverflow:
447 return os << "overflow";
448 case kNotOverflow:
449 return os << "not overflow";
450 }
451 UNREACHABLE();
452 return os;
453}
454
455
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400456std::ostream& operator<<(std::ostream& os,
457 const PrintableInstruction& printable) {
458 const Instruction& instr = *printable.instr_;
459 PrintableInstructionOperand printable_op = {printable.register_configuration_,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000460 InstructionOperand()};
461 os << "gap ";
462 for (int i = Instruction::FIRST_GAP_POSITION;
463 i <= Instruction::LAST_GAP_POSITION; i++) {
464 os << "(";
465 if (instr.parallel_moves()[i] != nullptr) {
466 PrintableParallelMove ppm = {printable.register_configuration_,
467 instr.parallel_moves()[i]};
468 os << ppm;
469 }
470 os << ") ";
471 }
472 os << "\n ";
473
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000474 if (instr.OutputCount() > 1) os << "(";
475 for (size_t i = 0; i < instr.OutputCount(); i++) {
476 if (i > 0) os << ", ";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000477 printable_op.op_ = *instr.OutputAt(i);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400478 os << printable_op;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000479 }
480
481 if (instr.OutputCount() > 1) os << ") = ";
482 if (instr.OutputCount() == 1) os << " = ";
483
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000484 os << ArchOpcodeField::decode(instr.opcode());
485 AddressingMode am = AddressingModeField::decode(instr.opcode());
486 if (am != kMode_None) {
487 os << " : " << AddressingModeField::decode(instr.opcode());
488 }
489 FlagsMode fm = FlagsModeField::decode(instr.opcode());
490 if (fm != kFlags_none) {
491 os << " && " << fm << " if " << FlagsConditionField::decode(instr.opcode());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000492 }
493 if (instr.InputCount() > 0) {
494 for (size_t i = 0; i < instr.InputCount(); i++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000495 printable_op.op_ = *instr.InputAt(i);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400496 os << " " << printable_op;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000497 }
498 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400499 return os;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000500}
501
502
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000503Constant::Constant(int32_t v) : type_(kInt32), value_(v) {}
504
505
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400506std::ostream& operator<<(std::ostream& os, const Constant& constant) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000507 switch (constant.type()) {
508 case Constant::kInt32:
509 return os << constant.ToInt32();
510 case Constant::kInt64:
511 return os << constant.ToInt64() << "l";
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400512 case Constant::kFloat32:
513 return os << constant.ToFloat32() << "f";
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000514 case Constant::kFloat64:
515 return os << constant.ToFloat64();
516 case Constant::kExternalReference:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400517 return os << static_cast<const void*>(
518 constant.ToExternalReference().address());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000519 case Constant::kHeapObject:
520 return os << Brief(*constant.ToHeapObject());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400521 case Constant::kRpoNumber:
522 return os << "RPO" << constant.ToRpoNumber().ToInt();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000523 }
524 UNREACHABLE();
525 return os;
526}
527
528
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000529PhiInstruction::PhiInstruction(Zone* zone, int virtual_register,
530 size_t input_count)
531 : virtual_register_(virtual_register),
532 output_(UnallocatedOperand(UnallocatedOperand::NONE, virtual_register)),
533 operands_(input_count, InstructionOperand::kInvalidVirtualRegister,
534 zone) {}
535
536
537void PhiInstruction::SetInput(size_t offset, int virtual_register) {
538 DCHECK_EQ(InstructionOperand::kInvalidVirtualRegister, operands_[offset]);
539 operands_[offset] = virtual_register;
540}
541
542
543InstructionBlock::InstructionBlock(Zone* zone, RpoNumber rpo_number,
544 RpoNumber loop_header, RpoNumber loop_end,
545 bool deferred, bool handler)
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400546 : successors_(zone),
547 predecessors_(zone),
548 phis_(zone),
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400549 ao_number_(rpo_number),
550 rpo_number_(rpo_number),
551 loop_header_(loop_header),
552 loop_end_(loop_end),
553 code_start_(-1),
554 code_end_(-1),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000555 deferred_(deferred),
556 handler_(handler),
557 needs_frame_(false),
558 must_construct_frame_(false),
559 must_deconstruct_frame_(false),
560 last_deferred_(RpoNumber::Invalid()) {}
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400561
562
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000563size_t InstructionBlock::PredecessorIndexOf(RpoNumber rpo_number) const {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400564 size_t j = 0;
565 for (InstructionBlock::Predecessors::const_iterator i = predecessors_.begin();
566 i != predecessors_.end(); ++i, ++j) {
567 if (*i == rpo_number) break;
568 }
569 return j;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000570}
571
572
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000573static RpoNumber GetRpo(const BasicBlock* block) {
574 if (block == nullptr) return RpoNumber::Invalid();
575 return RpoNumber::FromInt(block->rpo_number());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000576}
577
578
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000579static RpoNumber GetLoopEndRpo(const BasicBlock* block) {
580 if (!block->IsLoopHeader()) return RpoNumber::Invalid();
581 return RpoNumber::FromInt(block->loop_end()->rpo_number());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000582}
583
584
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400585static InstructionBlock* InstructionBlockFor(Zone* zone,
586 const BasicBlock* block) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000587 bool is_handler =
588 !block->empty() && block->front()->opcode() == IrOpcode::kIfException;
589 InstructionBlock* instr_block = new (zone)
590 InstructionBlock(zone, GetRpo(block), GetRpo(block->loop_header()),
591 GetLoopEndRpo(block), block->deferred(), is_handler);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400592 // Map successors and precessors
593 instr_block->successors().reserve(block->SuccessorCount());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000594 for (BasicBlock* successor : block->successors()) {
595 instr_block->successors().push_back(GetRpo(successor));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400596 }
597 instr_block->predecessors().reserve(block->PredecessorCount());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000598 for (BasicBlock* predecessor : block->predecessors()) {
599 instr_block->predecessors().push_back(GetRpo(predecessor));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400600 }
601 return instr_block;
602}
603
604
605InstructionBlocks* InstructionSequence::InstructionBlocksFor(
606 Zone* zone, const Schedule* schedule) {
607 InstructionBlocks* blocks = zone->NewArray<InstructionBlocks>(1);
608 new (blocks) InstructionBlocks(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000609 static_cast<int>(schedule->rpo_order()->size()), nullptr, zone);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400610 size_t rpo_number = 0;
611 for (BasicBlockVector::const_iterator it = schedule->rpo_order()->begin();
612 it != schedule->rpo_order()->end(); ++it, ++rpo_number) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000613 DCHECK(!(*blocks)[rpo_number]);
614 DCHECK(GetRpo(*it).ToSize() == rpo_number);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400615 (*blocks)[rpo_number] = InstructionBlockFor(zone, *it);
616 }
617 ComputeAssemblyOrder(blocks);
618 return blocks;
619}
620
Ben Murdoch097c5b22016-05-18 11:27:45 +0100621void InstructionSequence::Validate() {
622 // Validate blocks are in edge-split form: no block with multiple successors
623 // has an edge to a block (== a successor) with more than one predecessors.
624 for (const InstructionBlock* block : instruction_blocks()) {
625 if (block->SuccessorCount() > 1) {
626 for (const RpoNumber& successor_id : block->successors()) {
627 const InstructionBlock* successor = InstructionBlockAt(successor_id);
628 // Expect precisely one predecessor: "block".
629 CHECK(successor->PredecessorCount() == 1 &&
630 successor->predecessors()[0] == block->rpo_number());
631 }
632 }
633 }
634}
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400635
636void InstructionSequence::ComputeAssemblyOrder(InstructionBlocks* blocks) {
637 int ao = 0;
638 for (auto const block : *blocks) {
639 if (!block->IsDeferred()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000640 block->set_ao_number(RpoNumber::FromInt(ao++));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400641 }
642 }
643 for (auto const block : *blocks) {
644 if (block->IsDeferred()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000645 block->set_ao_number(RpoNumber::FromInt(ao++));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400646 }
647 }
648}
649
650
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000651InstructionSequence::InstructionSequence(Isolate* isolate,
652 Zone* instruction_zone,
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400653 InstructionBlocks* instruction_blocks)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000654 : isolate_(isolate),
655 zone_(instruction_zone),
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400656 instruction_blocks_(instruction_blocks),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000657 source_positions_(zone()),
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400658 block_starts_(zone()),
659 constants_(ConstantMap::key_compare(),
660 ConstantMap::allocator_type(zone())),
661 immediates_(zone()),
662 instructions_(zone()),
663 next_virtual_register_(0),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000664 reference_maps_(zone()),
665 representations_(zone()),
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400666 deoptimization_entries_(zone()) {
667 block_starts_.reserve(instruction_blocks_->size());
Ben Murdoch097c5b22016-05-18 11:27:45 +0100668
669#if DEBUG
670 Validate();
671#endif
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400672}
673
674
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000675int InstructionSequence::NextVirtualRegister() {
676 int virtual_register = next_virtual_register_++;
677 CHECK_NE(virtual_register, InstructionOperand::kInvalidVirtualRegister);
678 return virtual_register;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400679}
680
681
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000682Instruction* InstructionSequence::GetBlockStart(RpoNumber rpo) const {
683 const InstructionBlock* block = InstructionBlockAt(rpo);
684 return InstructionAt(block->code_start());
685}
686
687
688void InstructionSequence::StartBlock(RpoNumber rpo) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400689 DCHECK(block_starts_.size() == rpo.ToSize());
690 InstructionBlock* block = InstructionBlockAt(rpo);
691 int code_start = static_cast<int>(instructions_.size());
692 block->set_code_start(code_start);
693 block_starts_.push_back(code_start);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400694}
695
696
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000697void InstructionSequence::EndBlock(RpoNumber rpo) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000698 int end = static_cast<int>(instructions_.size());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400699 InstructionBlock* block = InstructionBlockAt(rpo);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000700 if (block->code_start() == end) { // Empty block. Insert a nop.
701 AddInstruction(Instruction::New(zone(), kArchNop));
702 end = static_cast<int>(instructions_.size());
703 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400704 DCHECK(block->code_start() >= 0 && block->code_start() < end);
705 block->set_code_end(end);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000706}
707
708
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400709int InstructionSequence::AddInstruction(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000710 int index = static_cast<int>(instructions_.size());
711 instructions_.push_back(instr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000712 if (instr->NeedsReferenceMap()) {
713 DCHECK(instr->reference_map() == nullptr);
714 ReferenceMap* reference_map = new (zone()) ReferenceMap(zone());
715 reference_map->set_instruction_position(index);
716 instr->set_reference_map(reference_map);
717 reference_maps_.push_back(reference_map);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000718 }
719 return index;
720}
721
722
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000723InstructionBlock* InstructionSequence::GetInstructionBlock(
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400724 int instruction_index) const {
725 DCHECK(instruction_blocks_->size() == block_starts_.size());
726 auto begin = block_starts_.begin();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000727 auto end = std::lower_bound(begin, block_starts_.end(), instruction_index);
728 // Post condition of std::lower_bound:
729 DCHECK(end == block_starts_.end() || *end >= instruction_index);
730 if (end == block_starts_.end() || *end > instruction_index) --end;
731 DCHECK(*end <= instruction_index);
732 size_t index = std::distance(begin, end);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400733 auto block = instruction_blocks_->at(index);
734 DCHECK(block->code_start() <= instruction_index &&
735 instruction_index < block->code_end());
736 return block;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000737}
738
739
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000740static MachineRepresentation FilterRepresentation(MachineRepresentation rep) {
741 switch (rep) {
742 case MachineRepresentation::kBit:
743 case MachineRepresentation::kWord8:
744 case MachineRepresentation::kWord16:
745 return InstructionSequence::DefaultRepresentation();
746 case MachineRepresentation::kWord32:
747 case MachineRepresentation::kWord64:
748 case MachineRepresentation::kFloat32:
749 case MachineRepresentation::kFloat64:
Ben Murdoch097c5b22016-05-18 11:27:45 +0100750 case MachineRepresentation::kSimd128:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000751 case MachineRepresentation::kTagged:
752 return rep;
753 case MachineRepresentation::kNone:
754 break;
755 }
756 UNREACHABLE();
757 return MachineRepresentation::kNone;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000758}
759
760
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000761MachineRepresentation InstructionSequence::GetRepresentation(
762 int virtual_register) const {
763 DCHECK_LE(0, virtual_register);
764 DCHECK_LT(virtual_register, VirtualRegisterCount());
765 if (virtual_register >= static_cast<int>(representations_.size())) {
766 return DefaultRepresentation();
767 }
768 return representations_[virtual_register];
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000769}
770
771
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000772void InstructionSequence::MarkAsRepresentation(MachineRepresentation rep,
773 int virtual_register) {
774 DCHECK_LE(0, virtual_register);
775 DCHECK_LT(virtual_register, VirtualRegisterCount());
776 if (virtual_register >= static_cast<int>(representations_.size())) {
777 representations_.resize(VirtualRegisterCount(), DefaultRepresentation());
778 }
779 rep = FilterRepresentation(rep);
780 DCHECK_IMPLIES(representations_[virtual_register] != rep,
781 representations_[virtual_register] == DefaultRepresentation());
782 representations_[virtual_register] = rep;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000783}
784
785
786InstructionSequence::StateId InstructionSequence::AddFrameStateDescriptor(
787 FrameStateDescriptor* descriptor) {
788 int deoptimization_id = static_cast<int>(deoptimization_entries_.size());
789 deoptimization_entries_.push_back(descriptor);
790 return StateId::FromInt(deoptimization_id);
791}
792
793FrameStateDescriptor* InstructionSequence::GetFrameStateDescriptor(
794 InstructionSequence::StateId state_id) {
795 return deoptimization_entries_[state_id.ToInt()];
796}
797
798
799int InstructionSequence::GetFrameStateDescriptorCount() {
800 return static_cast<int>(deoptimization_entries_.size());
801}
802
803
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000804RpoNumber InstructionSequence::InputRpo(Instruction* instr, size_t index) {
805 InstructionOperand* operand = instr->InputAt(index);
806 Constant constant =
807 operand->IsImmediate()
808 ? GetImmediate(ImmediateOperand::cast(operand))
809 : GetConstant(ConstantOperand::cast(operand)->virtual_register());
810 return constant.ToRpoNumber();
811}
812
813
814bool InstructionSequence::GetSourcePosition(const Instruction* instr,
815 SourcePosition* result) const {
816 auto it = source_positions_.find(instr);
817 if (it == source_positions_.end()) return false;
818 *result = it->second;
819 return true;
820}
821
822
823void InstructionSequence::SetSourcePosition(const Instruction* instr,
824 SourcePosition value) {
825 source_positions_.insert(std::make_pair(instr, value));
826}
827
828
829void InstructionSequence::Print(const RegisterConfiguration* config) const {
830 OFStream os(stdout);
831 PrintableInstructionSequence wrapper;
832 wrapper.register_configuration_ = config;
833 wrapper.sequence_ = this;
834 os << wrapper << std::endl;
835}
836
837
838void InstructionSequence::Print() const {
839 const RegisterConfiguration* config =
840 RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN);
841 Print(config);
842}
843
Ben Murdoch097c5b22016-05-18 11:27:45 +0100844void InstructionSequence::PrintBlock(const RegisterConfiguration* config,
845 int block_id) const {
846 OFStream os(stdout);
847 RpoNumber rpo = RpoNumber::FromInt(block_id);
848 const InstructionBlock* block = InstructionBlockAt(rpo);
849 CHECK(block->rpo_number() == rpo);
850
851 os << "B" << block->rpo_number();
852 os << ": AO#" << block->ao_number();
853 if (block->IsDeferred()) os << " (deferred)";
854 if (!block->needs_frame()) os << " (no frame)";
855 if (block->must_construct_frame()) os << " (construct frame)";
856 if (block->must_deconstruct_frame()) os << " (deconstruct frame)";
857 if (block->IsLoopHeader()) {
858 os << " loop blocks: [" << block->rpo_number() << ", " << block->loop_end()
859 << ")";
860 }
861 os << " instructions: [" << block->code_start() << ", " << block->code_end()
862 << ")\n predecessors:";
863
864 for (auto pred : block->predecessors()) {
865 os << " B" << pred.ToInt();
866 }
867 os << "\n";
868
869 for (auto phi : block->phis()) {
870 PrintableInstructionOperand printable_op = {config, phi->output()};
871 os << " phi: " << printable_op << " =";
872 for (auto input : phi->operands()) {
873 os << " v" << input;
874 }
875 os << "\n";
876 }
877
878 ScopedVector<char> buf(32);
879 PrintableInstruction printable_instr;
880 printable_instr.register_configuration_ = config;
881 for (int j = block->first_instruction_index();
882 j <= block->last_instruction_index(); j++) {
883 // TODO(svenpanne) Add some basic formatting to our streams.
884 SNPrintF(buf, "%5d", j);
885 printable_instr.instr_ = InstructionAt(j);
886 os << " " << buf.start() << ": " << printable_instr << "\n";
887 }
888
889 for (auto succ : block->successors()) {
890 os << " B" << succ.ToInt();
891 }
892 os << "\n";
893}
894
895void InstructionSequence::PrintBlock(int block_id) const {
896 const RegisterConfiguration* config =
897 RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN);
898 PrintBlock(config, block_id);
899}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000900
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400901FrameStateDescriptor::FrameStateDescriptor(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000902 Zone* zone, FrameStateType type, BailoutId bailout_id,
903 OutputFrameStateCombine state_combine, size_t parameters_count,
904 size_t locals_count, size_t stack_count,
905 MaybeHandle<SharedFunctionInfo> shared_info,
906 FrameStateDescriptor* outer_state)
907 : type_(type),
908 bailout_id_(bailout_id),
909 frame_state_combine_(state_combine),
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400910 parameters_count_(parameters_count),
911 locals_count_(locals_count),
912 stack_count_(stack_count),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000913 values_(zone),
914 shared_info_(shared_info),
915 outer_state_(outer_state) {}
916
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400917
918size_t FrameStateDescriptor::GetSize(OutputFrameStateCombine combine) const {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000919 size_t size = 1 + parameters_count() + locals_count() + stack_count() +
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400920 (HasContext() ? 1 : 0);
921 switch (combine.kind()) {
922 case OutputFrameStateCombine::kPushOutput:
923 size += combine.GetPushCount();
924 break;
925 case OutputFrameStateCombine::kPokeAt:
926 break;
927 }
928 return size;
929}
930
931
932size_t FrameStateDescriptor::GetTotalSize() const {
933 size_t total_size = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000934 for (const FrameStateDescriptor* iter = this; iter != nullptr;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400935 iter = iter->outer_state_) {
936 total_size += iter->GetSize();
937 }
938 return total_size;
939}
940
941
942size_t FrameStateDescriptor::GetFrameCount() const {
943 size_t count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000944 for (const FrameStateDescriptor* iter = this; iter != nullptr;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400945 iter = iter->outer_state_) {
946 ++count;
947 }
948 return count;
949}
950
951
952size_t FrameStateDescriptor::GetJSFrameCount() const {
953 size_t count = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000954 for (const FrameStateDescriptor* iter = this; iter != nullptr;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400955 iter = iter->outer_state_) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000956 if (FrameStateFunctionInfo::IsJSFunctionType(iter->type_)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400957 ++count;
958 }
959 }
960 return count;
961}
962
963
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000964std::ostream& operator<<(std::ostream& os, const RpoNumber& rpo) {
965 return os << rpo.ToSize();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400966}
967
968
969std::ostream& operator<<(std::ostream& os,
970 const PrintableInstructionSequence& printable) {
971 const InstructionSequence& code = *printable.sequence_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000972 for (size_t i = 0; i < code.immediates_.size(); ++i) {
973 Constant constant = code.immediates_[i];
974 os << "IMM#" << i << ": " << constant << "\n";
975 }
976 int i = 0;
977 for (ConstantMap::const_iterator it = code.constants_.begin();
978 it != code.constants_.end(); ++i, ++it) {
979 os << "CST#" << i << ": v" << it->first << " = " << it->second << "\n";
980 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400981 for (int i = 0; i < code.InstructionBlockCount(); i++) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100982 printable.sequence_->PrintBlock(printable.register_configuration_, i);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000983 }
984 return os;
985}
986
987} // namespace compiler
988} // namespace internal
989} // namespace v8