| 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 |