Commit 3065af53 authored by Thibaud Michaud's avatar Thibaud Michaud Committed by V8 LUCI CQ

[codegen] Fuzz gap resolver with codegen

The cctest test-code-generator/FuzzAssembleMove fuzzes codegen
for a random list of sequential moves by simulating the moves on a
FixedArray, and comparing the result to the output of the generated
code.

Add a variant of this test that resolves parallel moves first, to also
test integration with the gap resolver.

Bug: chromium:1313647
Change-Id: I02f385a957dafc89d91a4ab2216e0ac72147536d
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3660252Reviewed-by: 's avatarDarius Mercadier <dmercadier@chromium.org>
Commit-Queue: Thibaud Michaud <thibaudm@chromium.org>
Reviewed-by: 's avatarClemens Backes <clemensb@chromium.org>
Cr-Commit-Position: refs/heads/main@{#80774}
parent 9ed9dff9
......@@ -32,6 +32,16 @@ namespace compiler {
namespace {
enum MoveMode { kParallelMoves, kSequentialMoves };
ParallelMove* CopyMoves(ParallelMove* moves, Zone* zone) {
ParallelMove* copy = zone->New<ParallelMove>(zone);
for (auto m : *moves) {
copy->AddMove(m->source(), m->destination());
}
return copy;
}
int GetSlotSizeInBytes(MachineRepresentation rep) {
switch (rep) {
case MachineRepresentation::kTagged:
......@@ -720,7 +730,8 @@ class TestEnvironment : public HandleAndZoneScope {
// Perform the given list of moves on `state_in` and return a newly allocated
// state with the results.
Handle<FixedArray> SimulateMoves(ParallelMove* moves,
Handle<FixedArray> state_in) {
Handle<FixedArray> state_in,
MoveMode move_mode) {
Handle<FixedArray> state_out = main_isolate()->factory()->NewFixedArray(
static_cast<int>(layout_.size()));
// We do not want to modify `state_in` in place so perform the moves on a
......@@ -759,7 +770,9 @@ class TestEnvironment : public HandleAndZoneScope {
state_out->set(to_index, *constant_value);
} else {
int from_index = OperandToStatePosition(AllocatedOperand::cast(from));
state_out->set(to_index, state_out->get(from_index));
state_out->set(to_index, move_mode == kParallelMoves
? state_in->get(from_index)
: state_out->get(from_index));
}
}
return state_out;
......@@ -835,21 +848,48 @@ class TestEnvironment : public HandleAndZoneScope {
kCannotBeConstant
};
// Generate parallel moves at random. Note that they may not be compatible
// between each other as this doesn't matter to the code generator.
ParallelMove* GenerateRandomMoves(int size) {
// Generate parallel moves at random.
// In sequential mode, they can be incompatible between each other as this
// doesn't matter to the code generator.
// In parallel mode, ensure that two destinations can't conflict with each
// other, and pick sources among the compatible destinations if any, to
// increase the number of dependencies and stress the gap resolver.
ParallelMove* GenerateRandomMoves(int size, MoveMode move_mode) {
ParallelMove* parallel_move = main_zone()->New<ParallelMove>(main_zone());
std::map<MachineRepresentation, std::vector<InstructionOperand*>>
destinations;
for (int i = 0; i < size;) {
MachineRepresentation rep = CreateRandomMachineRepresentation();
MoveOperands mo(CreateRandomOperand(kNone, rep),
CreateRandomOperand(kCannotBeConstant, rep));
InstructionOperand source;
if (move_mode == kParallelMoves && !destinations[rep].empty()) {
// Try reusing a destination.
source = *destinations[rep][rng_->NextInt(
static_cast<int>(destinations[rep].size()))];
} else {
source = CreateRandomOperand(kNone, rep);
}
MoveOperands mo(source, CreateRandomOperand(kCannotBeConstant, rep));
// It isn't valid to call `AssembleMove` and `AssembleSwap` with redundant
// moves.
if (mo.IsRedundant()) continue;
parallel_move->AddMove(mo.source(), mo.destination());
// Do not generate parallel moves with conflicting destinations.
if (move_mode == kParallelMoves) {
bool conflict = std::any_of(
destinations.begin(), destinations.end(), [&mo](auto& p) {
return std::any_of(
p.second.begin(), p.second.end(), [&mo](auto& dest) {
return dest->InterferesWith(mo.destination());
});
});
if (conflict) continue;
}
MoveOperands* operands =
parallel_move->AddMove(mo.source(), mo.destination());
// Iterate only when a move was created.
i++;
destinations[rep].push_back(&operands->destination());
}
return parallel_move;
......@@ -1107,6 +1147,14 @@ class CodeGeneratorTester {
CHECK(generator_->tasm()->pc_offset() > start);
}
void CheckAssembleMoves(ParallelMove* moves) {
for (auto m : *moves) {
m->set_source(*MaybeTranslateSlot(&m->source()));
m->set_destination(*MaybeTranslateSlot(&m->destination()));
}
generator_->resolver()->Resolve(moves);
}
void CheckAssembleSwap(InstructionOperand* source,
InstructionOperand* destination) {
int start = generator_->tasm()->pc_offset();
......@@ -1210,9 +1258,10 @@ TEST(FuzzAssembleMove) {
TestEnvironment env;
Handle<FixedArray> state_in = env.GenerateInitialState();
ParallelMove* moves = env.GenerateRandomMoves(1000);
ParallelMove* moves = env.GenerateRandomMoves(1000, kSequentialMoves);
Handle<FixedArray> expected = env.SimulateMoves(moves, state_in);
Handle<FixedArray> expected =
env.SimulateMoves(moves, state_in, kSequentialMoves);
// Test small and potentially large ranges separately.
for (int extra_space : {0, kExtraSpace}) {
......@@ -1232,6 +1281,45 @@ TEST(FuzzAssembleMove) {
}
}
// Test integration with the gap resolver by resolving parallel moves first.
TEST(FuzzAssembleParallelMove) {
TestEnvironment env;
// Generate a sequence of N parallel moves of M moves each.
constexpr int N = 100;
constexpr int M = 10;
Handle<FixedArray> state_in = env.GenerateInitialState();
Handle<FixedArray> state_out =
env.main_isolate()->factory()->NewFixedArray(state_in->length());
state_in->CopyTo(0, *state_out, 0, state_in->length());
ParallelMove* moves[N];
for (int i = 0; i < N; ++i) {
moves[i] = env.GenerateRandomMoves(M, kParallelMoves);
state_out = env.SimulateMoves(moves[i], state_out, kParallelMoves);
}
// Test small and potentially large ranges separately.
for (int extra_space : {0, kExtraSpace}) {
CodeGeneratorTester c(&env, extra_space);
for (int i = 0; i < N; ++i) {
// The gap resolver modifies the parallel move in-place. Copy and restore
// it after assembling.
ParallelMove* save_moves = CopyMoves(moves[i], env.main_zone());
c.CheckAssembleMoves(moves[i]);
moves[i] = save_moves;
}
Handle<Code> test = c.FinalizeForExecuting();
if (FLAG_print_code) {
test->Print();
}
Handle<FixedArray> actual = env.Run(test, state_in);
env.CheckState(actual, state_out);
}
}
TEST(FuzzAssembleSwap) {
TestEnvironment env;
......@@ -1274,8 +1362,8 @@ TEST(FuzzAssembleMoveAndSwap) {
for (int i = 0; i < 1000; i++) {
// Randomly alternate between swaps and moves.
if (env.rng()->NextInt(2) == 0) {
ParallelMove* move = env.GenerateRandomMoves(1);
expected = env.SimulateMoves(move, expected);
ParallelMove* move = env.GenerateRandomMoves(1, kSequentialMoves);
expected = env.SimulateMoves(move, expected, kSequentialMoves);
c.CheckAssembleMove(&move->at(0)->source(),
&move->at(0)->destination());
} else {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment