|
22 | 22 | #include "gtest/gtest.h" |
23 | 23 | #include "absl/status/status_matchers.h" |
24 | 24 | #include "absl/status/statusor.h" |
| 25 | +#include "absl/strings/str_format.h" |
25 | 26 | #include "xls/common/file/get_runfile_path.h" |
26 | 27 | #include "xls/common/status/matchers.h" |
27 | 28 | #include "xls/common/status/status_macros.h" |
|
37 | 38 | #include "xls/ir/source_location.h" |
38 | 39 | #include "xls/ir/value.h" |
39 | 40 | #include "xls/passes/pass_base.h" |
| 41 | +#include "xls/scheduling/pipeline_schedule.h" |
40 | 42 | #include "xls/scheduling/scheduling_options.h" |
41 | 43 | #include "xls/scheduling/scheduling_pass.h" |
42 | 44 |
|
@@ -431,5 +433,114 @@ TEST_F(PipelineSchedulingPassTest, MultiProcScopedChannels) { |
431 | 433 | SchedulingOptions().pipeline_stages(2).schedule_all_procs(true))); |
432 | 434 | } |
433 | 435 |
|
| 436 | +TEST_F(PipelineSchedulingPassTest, MinimizeClockOnFailure) { |
| 437 | + auto p = CreatePackage(); |
| 438 | + FunctionBuilder fb("main", p.get()); |
| 439 | + BValue x = fb.Param("x", p->GetBitsType(32)); |
| 440 | + BValue y = fb.Param("y", p->GetBitsType(32)); |
| 441 | + BValue add = fb.Add(x, y); |
| 442 | + BValue div = fb.UDiv(x, y); |
| 443 | + BValue div_two = fb.UDiv(x, div); |
| 444 | + BValue ored = fb.Or({add, div_two}); |
| 445 | + XLS_ASSERT_OK_AND_ASSIGN(Function * f, fb.BuildWithReturnValue(ored)); |
| 446 | + |
| 447 | + // Fail if trying to schedule with a clock period that is too small. |
| 448 | + auto failed_scheduled_result = RunPipelineSchedulingPass( |
| 449 | + f, SchedulingOptions().clock_period_ps(1).pipeline_stages(2)); |
| 450 | + EXPECT_THAT(failed_scheduled_result.status().message(), |
| 451 | + AllOf(HasSubstr("cannot achieve the specified clock period"), |
| 452 | + HasSubstr("clock_period_ps=3"))); |
| 453 | + |
| 454 | + // Succeed if trying to schedule with a large enough clock period. |
| 455 | + XLS_ASSERT_OK_AND_ASSIGN( |
| 456 | + auto success_scheduled_result, |
| 457 | + RunPipelineSchedulingPass( |
| 458 | + f, SchedulingOptions().clock_period_ps(3).pipeline_stages(2))); |
| 459 | + EXPECT_THAT(success_scheduled_result, |
| 460 | + Pair(true, SchedulingContextWithElements(UnorderedElementsAre( |
| 461 | + Pair(f, VerifiedPipelineSchedule()))))); |
| 462 | + PipelineSchedule f_schedule = |
| 463 | + success_scheduled_result.second.package_schedule().GetSchedule(f); |
| 464 | + EXPECT_THAT( |
| 465 | + f_schedule.GetCycleMap(), |
| 466 | + UnorderedElementsAre(Pair(x.node(), 0), Pair(y.node(), 0), |
| 467 | + Pair(add.node(), 0), Pair(div.node(), 0), |
| 468 | + Pair(div_two.node(), 1), Pair(ored.node(), 1))); |
| 469 | +} |
| 470 | + |
| 471 | +TEST_F(PipelineSchedulingPassTest, MinimizeClockOnFailureWithIOConstraints) { |
| 472 | + auto p = CreatePackage(); |
| 473 | + auto make_proc = [p = p.get()]( |
| 474 | + std::string_view name, Channel* channel_in, |
| 475 | + Channel* channel_out) -> absl::StatusOr<Proc*> { |
| 476 | + ProcBuilder pb(name, p); |
| 477 | + BValue tok = pb.Literal(Value::Token()); |
| 478 | + BValue st = pb.StateElement("st", Value(UBits(0, 32))); |
| 479 | + BValue recv = pb.Receive(channel_in, tok, SourceInfo(), "recv"); |
| 480 | + BValue recv_tok = pb.TupleIndex(recv, 0); |
| 481 | + BValue recv_data = pb.TupleIndex(recv, 1); |
| 482 | + for (int i = 0; i < 3; ++i) { |
| 483 | + recv_data = pb.Add(recv_data, pb.Literal(UBits(1, 32))); |
| 484 | + recv_data = pb.Subtract(recv_data, pb.Literal(UBits(1, 32))); |
| 485 | + } |
| 486 | + BValue add_st = pb.Add(st, recv_data); |
| 487 | + pb.Send(channel_out, recv_tok, add_st, SourceInfo(), "send"); |
| 488 | + return pb.Build({add_st}); |
| 489 | + }; |
| 490 | + |
| 491 | + XLS_ASSERT_OK_AND_ASSIGN( |
| 492 | + Channel * ch0, p->CreateStreamingChannel("ch0", ChannelOps::kReceiveOnly, |
| 493 | + p->GetBitsType(32))); |
| 494 | + XLS_ASSERT_OK_AND_ASSIGN( |
| 495 | + Channel * ch1, p->CreateStreamingChannel("ch1", ChannelOps::kSendReceive, |
| 496 | + p->GetBitsType(32))); |
| 497 | + XLS_ASSERT_OK_AND_ASSIGN( |
| 498 | + Channel * ch2, p->CreateStreamingChannel("ch2", ChannelOps::kSendOnly, |
| 499 | + p->GetBitsType(32))); |
| 500 | + |
| 501 | + XLS_ASSERT_OK(make_proc("proc0", ch0, ch1)); |
| 502 | + XLS_ASSERT_OK(make_proc("proc1", ch1, ch2)); |
| 503 | + |
| 504 | + auto failed_result = RunPipelineSchedulingPass( |
| 505 | + p.get(), SchedulingOptions() |
| 506 | + .clock_period_ps(2) |
| 507 | + .pipeline_stages(4) |
| 508 | + .add_constraint(IOConstraint( |
| 509 | + /*source_channel=*/"ch0", |
| 510 | + /*source_direction=*/IODirection::kReceive, |
| 511 | + /*target_channel=*/"ch1", |
| 512 | + /*target_direction=*/IODirection::kSend, |
| 513 | + /*minimum_latency=*/1, /*maximum_latency=*/1)) |
| 514 | + .add_constraint(IOConstraint( |
| 515 | + /*source_channel=*/"ch1", |
| 516 | + /*source_direction=*/IODirection::kReceive, |
| 517 | + /*target_channel=*/"ch2", |
| 518 | + /*target_direction=*/IODirection::kSend, |
| 519 | + /*minimum_latency=*/1, /*maximum_latency=*/1))); |
| 520 | + EXPECT_THAT( |
| 521 | + failed_result.status().message(), |
| 522 | + AllOf(HasSubstr("cannot achieve the specified clock period"), |
| 523 | + HasSubstr("clock_period_ps=4"), |
| 524 | + HasSubstr("cannot satisfy the given I/O constraints. Would succeed " |
| 525 | + "with: {ch0→ch1 with maximum latency ≥ 3}"))); |
| 526 | + |
| 527 | + XLS_ASSERT_OK(RunPipelineSchedulingPass( |
| 528 | + p.get(), SchedulingOptions() |
| 529 | + .clock_period_ps(4) |
| 530 | + .pipeline_stages(4) |
| 531 | + .add_constraint(IOConstraint( |
| 532 | + /*source_channel=*/"ch0", |
| 533 | + /*source_direction=*/IODirection::kReceive, |
| 534 | + /*target_channel=*/"ch1", |
| 535 | + /*target_direction=*/IODirection::kSend, |
| 536 | + /*minimum_latency=*/1, /*maximum_latency=*/1)) |
| 537 | + .add_constraint(IOConstraint( |
| 538 | + /*source_channel=*/"ch1", |
| 539 | + /*source_direction=*/IODirection::kReceive, |
| 540 | + /*target_channel=*/"ch2", |
| 541 | + /*target_direction=*/IODirection::kSend, |
| 542 | + /*minimum_latency=*/1, /*maximum_latency=*/1)))); |
| 543 | +} |
| 544 | + |
434 | 545 | } // namespace |
435 | 546 | } // namespace xls |
0 commit comments