Index: test/cctest/compiler/test-gap-resolver.cc |
diff --git a/test/cctest/compiler/test-gap-resolver.cc b/test/cctest/compiler/test-gap-resolver.cc |
index 3b1cdb6d814fd1274bb9180d877c302b27a7c683..1cceb9cd59a3bc40225bdaba98e897e8c94f0b5f 100644 |
--- a/test/cctest/compiler/test-gap-resolver.cc |
+++ b/test/cctest/compiler/test-gap-resolver.cc |
@@ -13,15 +13,32 @@ namespace compiler { |
const auto GetRegConfig = RegisterConfiguration::Turbofan; |
-// Fragments the given operand into an equivalent set of operands to simplify |
-// ParallelMove equivalence testing. |
+// Fragments the given FP operand into an equivalent set of FP operands to |
+// simplify ParallelMove equivalence testing. |
void GetCanonicalOperands(const InstructionOperand& op, |
std::vector<InstructionOperand>* fragments) { |
CHECK(!kSimpleFPAliasing); |
CHECK(op.IsFPLocationOperand()); |
- // TODO(bbudge) Split into float operands on platforms with non-simple FP |
- // register aliasing. |
- fragments->push_back(op); |
+ const LocationOperand& loc = LocationOperand::cast(op); |
+ MachineRepresentation rep = loc.representation(); |
+ int base = -1; |
+ int aliases = GetRegConfig()->GetAliases( |
+ rep, 0, MachineRepresentation::kFloat32, &base); |
+ CHECK_LT(0, aliases); |
+ CHECK_GE(4, aliases); |
+ int index = -1; |
+ int step = 1; |
+ if (op.IsFPRegister()) { |
+ index = loc.register_code() * aliases; |
+ } else { |
+ index = loc.index(); |
+ step = -1; |
+ } |
+ for (int i = 0; i < aliases; i++) { |
+ fragments->push_back(AllocatedOperand(loc.location_kind(), |
+ MachineRepresentation::kFloat32, |
+ index + i * step)); |
+ } |
} |
// The state of our move interpreter is the mapping of operands to values. Note |
@@ -36,7 +53,9 @@ class InterpreterState { |
const InstructionOperand& dst = m->destination(); |
if (!kSimpleFPAliasing && src.IsFPLocationOperand() && |
dst.IsFPLocationOperand()) { |
- // Canonicalize FP location-location moves. |
+ // Canonicalize FP location-location moves by fragmenting them into |
+ // an equivalent sequence of float32 moves, to simplify state |
+ // equivalence testing. |
std::vector<InstructionOperand> src_fragments; |
GetCanonicalOperands(src, &src_fragments); |
CHECK(!src_fragments.empty()); |
@@ -115,9 +134,11 @@ class InterpreterState { |
int index; |
if (!is_constant) { |
const LocationOperand& loc_op = LocationOperand::cast(op); |
- // Canonicalize FP location operand representations to kFloat64. |
+ // Preserve FP representation when FP register aliasing is complex. |
+ // Otherwise, canonicalize to kFloat64. |
if (IsFloatingPoint(loc_op.representation())) { |
- rep = MachineRepresentation::kFloat64; |
+ rep = kSimpleFPAliasing ? MachineRepresentation::kFloat64 |
+ : loc_op.representation(); |
} |
if (loc_op.IsAnyRegister()) { |
index = loc_op.register_code(); |
@@ -321,9 +342,11 @@ class ParallelMoveCreator : public HandleAndZoneScope { |
auto GetValidRegisterCode = [&conf](MachineRepresentation rep, int index) { |
switch (rep) { |
case MachineRepresentation::kFloat32: |
+ return conf->RegisterConfiguration::GetAllocatableFloatCode(index); |
case MachineRepresentation::kFloat64: |
- case MachineRepresentation::kSimd128: |
return conf->RegisterConfiguration::GetAllocatableDoubleCode(index); |
+ case MachineRepresentation::kSimd128: |
+ return conf->RegisterConfiguration::GetAllocatableSimd128Code(index); |
default: |
return conf->RegisterConfiguration::GetAllocatableGeneralCode(index); |
} |
@@ -368,6 +391,118 @@ void RunTest(ParallelMove* pm, Zone* zone) { |
CHECK_EQ(mi1.state(), mi2.state()); |
} |
+TEST(Aliasing) { |
+ // On platforms with simple aliasing, these parallel moves are ill-formed. |
+ if (kSimpleFPAliasing) return; |
+ |
+ ParallelMoveCreator pmc; |
+ Zone* zone = pmc.main_zone(); |
+ |
+ auto s0 = AllocatedOperand(LocationOperand::REGISTER, |
+ MachineRepresentation::kFloat32, 0); |
+ auto s1 = AllocatedOperand(LocationOperand::REGISTER, |
+ MachineRepresentation::kFloat32, 1); |
+ auto s2 = AllocatedOperand(LocationOperand::REGISTER, |
+ MachineRepresentation::kFloat32, 2); |
+ auto s3 = AllocatedOperand(LocationOperand::REGISTER, |
+ MachineRepresentation::kFloat32, 3); |
+ auto s4 = AllocatedOperand(LocationOperand::REGISTER, |
+ MachineRepresentation::kFloat32, 4); |
+ |
+ auto d0 = AllocatedOperand(LocationOperand::REGISTER, |
+ MachineRepresentation::kFloat64, 0); |
+ auto d1 = AllocatedOperand(LocationOperand::REGISTER, |
+ MachineRepresentation::kFloat64, 1); |
+ auto d16 = AllocatedOperand(LocationOperand::REGISTER, |
+ MachineRepresentation::kFloat64, 16); |
+ |
+ // Double slots must be odd to match frame allocation. |
+ auto dSlot = AllocatedOperand(LocationOperand::STACK_SLOT, |
+ MachineRepresentation::kFloat64, 3); |
+ |
+ // Cycles involving s- and d-registers. |
+ { |
+ std::vector<InstructionOperand> moves = { |
+ s2, s0, // s2 <- s0 |
+ d0, d1 // d0 <- d1 |
+ }; |
+ RunTest(pmc.Create(moves), zone); |
+ } |
+ { |
+ std::vector<InstructionOperand> moves = { |
+ d0, d1, // d0 <- d1 |
+ s2, s0 // s2 <- s0 |
+ }; |
+ RunTest(pmc.Create(moves), zone); |
+ } |
+ { |
+ std::vector<InstructionOperand> moves = { |
+ s2, s1, // s2 <- s1 |
+ d0, d1 // d0 <- d1 |
+ }; |
+ RunTest(pmc.Create(moves), zone); |
+ } |
+ { |
+ std::vector<InstructionOperand> moves = { |
+ d0, d1, // d0 <- d1 |
+ s2, s1 // s2 <- s1 |
+ }; |
+ RunTest(pmc.Create(moves), zone); |
+ } |
+ // Two cycles involving a single d-register. |
+ { |
+ std::vector<InstructionOperand> moves = { |
+ d0, d1, // d0 <- d1 |
+ s2, s1, // s2 <- s1 |
+ s3, s0 // s3 <- s0 |
+ }; |
+ RunTest(pmc.Create(moves), zone); |
+ } |
+ // Cycle with a float move that must be deferred until after swaps. |
+ { |
+ std::vector<InstructionOperand> moves = { |
+ d0, d1, // d0 <- d1 |
+ s2, s0, // s2 <- s0 |
+ s3, s4 // s3 <- s4 must be deferred |
+ }; |
+ RunTest(pmc.Create(moves), zone); |
+ } |
+ // Cycles involving s-registers and a non-aliased d-register. |
+ { |
+ std::vector<InstructionOperand> moves = { |
+ d16, d0, // d16 <- d0 |
+ s1, s2, // s1 <- s2 |
+ d1, d16 // d1 <- d16 |
+ }; |
+ RunTest(pmc.Create(moves), zone); |
+ } |
+ { |
+ std::vector<InstructionOperand> moves = { |
+ s2, s1, // s1 <- s2 |
+ d0, d16, // d16 <- d0 |
+ d16, d1 // d1 <- d16 |
+ }; |
+ RunTest(pmc.Create(moves), zone); |
+ } |
+ { |
+ std::vector<InstructionOperand> moves = { |
+ d0, d16, // d0 <- d16 |
+ d16, d1, // s2 <- s0 |
+ s3, s0 // d0 <- d1 |
+ }; |
+ RunTest(pmc.Create(moves), zone); |
+ } |
+ // Cycle involving aliasing registers and a slot. |
+ { |
+ std::vector<InstructionOperand> moves = { |
+ dSlot, d0, // dSlot <- d0 |
+ d1, dSlot, // d1 <- dSlot |
+ s0, s3 // s0 <- s3 |
+ }; |
+ RunTest(pmc.Create(moves), zone); |
+ } |
+} |
+ |
TEST(FuzzResolver) { |
ParallelMoveCreator pmc; |
for (int size = 0; size < 80; ++size) { |