OLD | NEW |
1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/compiler/gap-resolver.h" | 5 #include "src/compiler/gap-resolver.h" |
6 | 6 |
7 #include "src/base/utils/random-number-generator.h" | 7 #include "src/base/utils/random-number-generator.h" |
8 #include "test/cctest/cctest.h" | 8 #include "test/cctest/cctest.h" |
9 | 9 |
10 namespace v8 { | 10 namespace v8 { |
11 namespace internal { | 11 namespace internal { |
12 namespace compiler { | 12 namespace compiler { |
13 | 13 |
14 const auto GetRegConfig = RegisterConfiguration::Turbofan; | 14 const auto GetRegConfig = RegisterConfiguration::Turbofan; |
15 | 15 |
16 // Fragments the given operand into an equivalent set of operands to simplify | 16 // Fragments the given FP operand into an equivalent set of FP operands to |
17 // ParallelMove equivalence testing. | 17 // simplify ParallelMove equivalence testing. |
18 void GetCanonicalOperands(const InstructionOperand& op, | 18 void GetCanonicalOperands(const InstructionOperand& op, |
19 std::vector<InstructionOperand>* fragments) { | 19 std::vector<InstructionOperand>* fragments) { |
20 CHECK(!kSimpleFPAliasing); | 20 CHECK(!kSimpleFPAliasing); |
21 CHECK(op.IsFPLocationOperand()); | 21 CHECK(op.IsFPLocationOperand()); |
22 // TODO(bbudge) Split into float operands on platforms with non-simple FP | 22 const LocationOperand& loc = LocationOperand::cast(op); |
23 // register aliasing. | 23 MachineRepresentation rep = loc.representation(); |
24 fragments->push_back(op); | 24 int base = -1; |
| 25 int aliases = GetRegConfig()->GetAliases( |
| 26 rep, 0, MachineRepresentation::kFloat32, &base); |
| 27 CHECK_LT(0, aliases); |
| 28 CHECK_GE(4, aliases); |
| 29 int index = -1; |
| 30 int step = 1; |
| 31 if (op.IsFPRegister()) { |
| 32 index = loc.register_code() * aliases; |
| 33 } else { |
| 34 index = loc.index(); |
| 35 step = -1; |
| 36 } |
| 37 for (int i = 0; i < aliases; i++) { |
| 38 fragments->push_back(AllocatedOperand(loc.location_kind(), |
| 39 MachineRepresentation::kFloat32, |
| 40 index + i * step)); |
| 41 } |
25 } | 42 } |
26 | 43 |
27 // The state of our move interpreter is the mapping of operands to values. Note | 44 // The state of our move interpreter is the mapping of operands to values. Note |
28 // that the actual values don't really matter, all we care about is equality. | 45 // that the actual values don't really matter, all we care about is equality. |
29 class InterpreterState { | 46 class InterpreterState { |
30 public: | 47 public: |
31 void ExecuteInParallel(const ParallelMove* moves) { | 48 void ExecuteInParallel(const ParallelMove* moves) { |
32 InterpreterState copy(*this); | 49 InterpreterState copy(*this); |
33 for (const auto m : *moves) { | 50 for (const auto m : *moves) { |
34 CHECK(!m->IsRedundant()); | 51 CHECK(!m->IsRedundant()); |
35 const InstructionOperand& src = m->source(); | 52 const InstructionOperand& src = m->source(); |
36 const InstructionOperand& dst = m->destination(); | 53 const InstructionOperand& dst = m->destination(); |
37 if (!kSimpleFPAliasing && src.IsFPLocationOperand() && | 54 if (!kSimpleFPAliasing && src.IsFPLocationOperand() && |
38 dst.IsFPLocationOperand()) { | 55 dst.IsFPLocationOperand()) { |
39 // Canonicalize FP location-location moves. | 56 // Canonicalize FP location-location moves by fragmenting them into |
| 57 // an equivalent sequence of float32 moves, to simplify state |
| 58 // equivalence testing. |
40 std::vector<InstructionOperand> src_fragments; | 59 std::vector<InstructionOperand> src_fragments; |
41 GetCanonicalOperands(src, &src_fragments); | 60 GetCanonicalOperands(src, &src_fragments); |
42 CHECK(!src_fragments.empty()); | 61 CHECK(!src_fragments.empty()); |
43 std::vector<InstructionOperand> dst_fragments; | 62 std::vector<InstructionOperand> dst_fragments; |
44 GetCanonicalOperands(dst, &dst_fragments); | 63 GetCanonicalOperands(dst, &dst_fragments); |
45 CHECK_EQ(src_fragments.size(), dst_fragments.size()); | 64 CHECK_EQ(src_fragments.size(), dst_fragments.size()); |
46 | 65 |
47 for (size_t i = 0; i < src_fragments.size(); ++i) { | 66 for (size_t i = 0; i < src_fragments.size(); ++i) { |
48 write(dst_fragments[i], copy.read(src_fragments[i])); | 67 write(dst_fragments[i], copy.read(src_fragments[i])); |
49 } | 68 } |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
108 } | 127 } |
109 | 128 |
110 static Key KeyFor(const InstructionOperand& op) { | 129 static Key KeyFor(const InstructionOperand& op) { |
111 bool is_constant = op.IsConstant(); | 130 bool is_constant = op.IsConstant(); |
112 MachineRepresentation rep = | 131 MachineRepresentation rep = |
113 v8::internal::compiler::InstructionSequence::DefaultRepresentation(); | 132 v8::internal::compiler::InstructionSequence::DefaultRepresentation(); |
114 LocationOperand::LocationKind kind; | 133 LocationOperand::LocationKind kind; |
115 int index; | 134 int index; |
116 if (!is_constant) { | 135 if (!is_constant) { |
117 const LocationOperand& loc_op = LocationOperand::cast(op); | 136 const LocationOperand& loc_op = LocationOperand::cast(op); |
118 // Canonicalize FP location operand representations to kFloat64. | 137 // Preserve FP representation when FP register aliasing is complex. |
| 138 // Otherwise, canonicalize to kFloat64. |
119 if (IsFloatingPoint(loc_op.representation())) { | 139 if (IsFloatingPoint(loc_op.representation())) { |
120 rep = MachineRepresentation::kFloat64; | 140 rep = kSimpleFPAliasing ? MachineRepresentation::kFloat64 |
| 141 : loc_op.representation(); |
121 } | 142 } |
122 if (loc_op.IsAnyRegister()) { | 143 if (loc_op.IsAnyRegister()) { |
123 index = loc_op.register_code(); | 144 index = loc_op.register_code(); |
124 } else { | 145 } else { |
125 index = loc_op.index(); | 146 index = loc_op.index(); |
126 } | 147 } |
127 kind = loc_op.location_kind(); | 148 kind = loc_op.location_kind(); |
128 } else { | 149 } else { |
129 index = ConstantOperand::cast(op).virtual_register(); | 150 index = ConstantOperand::cast(op).virtual_register(); |
130 kind = LocationOperand::REGISTER; | 151 kind = LocationOperand::REGISTER; |
(...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
314 CHECK_EQ(MachineRepresentation::kSimd128, rep); | 335 CHECK_EQ(MachineRepresentation::kSimd128, rep); |
315 return base + index * 4; | 336 return base + index * 4; |
316 } | 337 } |
317 | 338 |
318 InstructionOperand CreateRandomOperand(bool is_source, | 339 InstructionOperand CreateRandomOperand(bool is_source, |
319 MachineRepresentation rep) { | 340 MachineRepresentation rep) { |
320 auto conf = RegisterConfiguration::Turbofan(); | 341 auto conf = RegisterConfiguration::Turbofan(); |
321 auto GetValidRegisterCode = [&conf](MachineRepresentation rep, int index) { | 342 auto GetValidRegisterCode = [&conf](MachineRepresentation rep, int index) { |
322 switch (rep) { | 343 switch (rep) { |
323 case MachineRepresentation::kFloat32: | 344 case MachineRepresentation::kFloat32: |
| 345 return conf->RegisterConfiguration::GetAllocatableFloatCode(index); |
324 case MachineRepresentation::kFloat64: | 346 case MachineRepresentation::kFloat64: |
| 347 return conf->RegisterConfiguration::GetAllocatableDoubleCode(index); |
325 case MachineRepresentation::kSimd128: | 348 case MachineRepresentation::kSimd128: |
326 return conf->RegisterConfiguration::GetAllocatableDoubleCode(index); | 349 return conf->RegisterConfiguration::GetAllocatableSimd128Code(index); |
327 default: | 350 default: |
328 return conf->RegisterConfiguration::GetAllocatableGeneralCode(index); | 351 return conf->RegisterConfiguration::GetAllocatableGeneralCode(index); |
329 } | 352 } |
330 UNREACHABLE(); | 353 UNREACHABLE(); |
331 return static_cast<int>(Register::kCode_no_reg); | 354 return static_cast<int>(Register::kCode_no_reg); |
332 }; | 355 }; |
333 int index = rng_->NextInt(kMaxIndex); | 356 int index = rng_->NextInt(kMaxIndex); |
334 // destination can't be Constant. | 357 // destination can't be Constant. |
335 switch (rng_->NextInt(is_source ? 5 : 4)) { | 358 switch (rng_->NextInt(is_source ? 5 : 4)) { |
336 case 0: | 359 case 0: |
(...skipping 24 matching lines...) Expand all Loading... |
361 MoveInterpreter mi1(zone); | 384 MoveInterpreter mi1(zone); |
362 mi1.AssembleParallelMove(pm); | 385 mi1.AssembleParallelMove(pm); |
363 | 386 |
364 MoveInterpreter mi2(zone); | 387 MoveInterpreter mi2(zone); |
365 GapResolver resolver(&mi2); | 388 GapResolver resolver(&mi2); |
366 resolver.Resolve(pm); | 389 resolver.Resolve(pm); |
367 | 390 |
368 CHECK_EQ(mi1.state(), mi2.state()); | 391 CHECK_EQ(mi1.state(), mi2.state()); |
369 } | 392 } |
370 | 393 |
| 394 TEST(Aliasing) { |
| 395 // On platforms with simple aliasing, these parallel moves are ill-formed. |
| 396 if (kSimpleFPAliasing) return; |
| 397 |
| 398 ParallelMoveCreator pmc; |
| 399 Zone* zone = pmc.main_zone(); |
| 400 |
| 401 auto s0 = AllocatedOperand(LocationOperand::REGISTER, |
| 402 MachineRepresentation::kFloat32, 0); |
| 403 auto s1 = AllocatedOperand(LocationOperand::REGISTER, |
| 404 MachineRepresentation::kFloat32, 1); |
| 405 auto s2 = AllocatedOperand(LocationOperand::REGISTER, |
| 406 MachineRepresentation::kFloat32, 2); |
| 407 auto s3 = AllocatedOperand(LocationOperand::REGISTER, |
| 408 MachineRepresentation::kFloat32, 3); |
| 409 auto s4 = AllocatedOperand(LocationOperand::REGISTER, |
| 410 MachineRepresentation::kFloat32, 4); |
| 411 |
| 412 auto d0 = AllocatedOperand(LocationOperand::REGISTER, |
| 413 MachineRepresentation::kFloat64, 0); |
| 414 auto d1 = AllocatedOperand(LocationOperand::REGISTER, |
| 415 MachineRepresentation::kFloat64, 1); |
| 416 auto d16 = AllocatedOperand(LocationOperand::REGISTER, |
| 417 MachineRepresentation::kFloat64, 16); |
| 418 |
| 419 // Double slots must be odd to match frame allocation. |
| 420 auto dSlot = AllocatedOperand(LocationOperand::STACK_SLOT, |
| 421 MachineRepresentation::kFloat64, 3); |
| 422 |
| 423 // Cycles involving s- and d-registers. |
| 424 { |
| 425 std::vector<InstructionOperand> moves = { |
| 426 s2, s0, // s2 <- s0 |
| 427 d0, d1 // d0 <- d1 |
| 428 }; |
| 429 RunTest(pmc.Create(moves), zone); |
| 430 } |
| 431 { |
| 432 std::vector<InstructionOperand> moves = { |
| 433 d0, d1, // d0 <- d1 |
| 434 s2, s0 // s2 <- s0 |
| 435 }; |
| 436 RunTest(pmc.Create(moves), zone); |
| 437 } |
| 438 { |
| 439 std::vector<InstructionOperand> moves = { |
| 440 s2, s1, // s2 <- s1 |
| 441 d0, d1 // d0 <- d1 |
| 442 }; |
| 443 RunTest(pmc.Create(moves), zone); |
| 444 } |
| 445 { |
| 446 std::vector<InstructionOperand> moves = { |
| 447 d0, d1, // d0 <- d1 |
| 448 s2, s1 // s2 <- s1 |
| 449 }; |
| 450 RunTest(pmc.Create(moves), zone); |
| 451 } |
| 452 // Two cycles involving a single d-register. |
| 453 { |
| 454 std::vector<InstructionOperand> moves = { |
| 455 d0, d1, // d0 <- d1 |
| 456 s2, s1, // s2 <- s1 |
| 457 s3, s0 // s3 <- s0 |
| 458 }; |
| 459 RunTest(pmc.Create(moves), zone); |
| 460 } |
| 461 // Cycle with a float move that must be deferred until after swaps. |
| 462 { |
| 463 std::vector<InstructionOperand> moves = { |
| 464 d0, d1, // d0 <- d1 |
| 465 s2, s0, // s2 <- s0 |
| 466 s3, s4 // s3 <- s4 must be deferred |
| 467 }; |
| 468 RunTest(pmc.Create(moves), zone); |
| 469 } |
| 470 // Cycles involving s-registers and a non-aliased d-register. |
| 471 { |
| 472 std::vector<InstructionOperand> moves = { |
| 473 d16, d0, // d16 <- d0 |
| 474 s1, s2, // s1 <- s2 |
| 475 d1, d16 // d1 <- d16 |
| 476 }; |
| 477 RunTest(pmc.Create(moves), zone); |
| 478 } |
| 479 { |
| 480 std::vector<InstructionOperand> moves = { |
| 481 s2, s1, // s1 <- s2 |
| 482 d0, d16, // d16 <- d0 |
| 483 d16, d1 // d1 <- d16 |
| 484 }; |
| 485 RunTest(pmc.Create(moves), zone); |
| 486 } |
| 487 { |
| 488 std::vector<InstructionOperand> moves = { |
| 489 d0, d16, // d0 <- d16 |
| 490 d16, d1, // s2 <- s0 |
| 491 s3, s0 // d0 <- d1 |
| 492 }; |
| 493 RunTest(pmc.Create(moves), zone); |
| 494 } |
| 495 // Cycle involving aliasing registers and a slot. |
| 496 { |
| 497 std::vector<InstructionOperand> moves = { |
| 498 dSlot, d0, // dSlot <- d0 |
| 499 d1, dSlot, // d1 <- dSlot |
| 500 s0, s3 // s0 <- s3 |
| 501 }; |
| 502 RunTest(pmc.Create(moves), zone); |
| 503 } |
| 504 } |
| 505 |
371 TEST(FuzzResolver) { | 506 TEST(FuzzResolver) { |
372 ParallelMoveCreator pmc; | 507 ParallelMoveCreator pmc; |
373 for (int size = 0; size < 80; ++size) { | 508 for (int size = 0; size < 80; ++size) { |
374 for (int repeat = 0; repeat < 50; ++repeat) { | 509 for (int repeat = 0; repeat < 50; ++repeat) { |
375 RunTest(pmc.Create(size), pmc.main_zone()); | 510 RunTest(pmc.Create(size), pmc.main_zone()); |
376 } | 511 } |
377 } | 512 } |
378 } | 513 } |
379 | 514 |
380 } // namespace compiler | 515 } // namespace compiler |
381 } // namespace internal | 516 } // namespace internal |
382 } // namespace v8 | 517 } // namespace v8 |
OLD | NEW |