72 if (is_constant(rvsdg::TryGetOwnerNode<rvsdg::SimpleNode>(*out)))
76 auto [forkNode, forkOperation] = rvsdg::TryGetSimpleNodeAndOptionalOp<ForkOperation>(*out);
77 if (forkOperation && forkOperation->IsConstant())
83 auto [bufferNode, bufferOperation] = rvsdg::TryGetSimpleNodeAndOptionalOp<BufferOperation>(*user);
85 && (bufferOperation->IsPassThrough() != passThrough
86 || bufferOperation->Capacity() != capacity))
89 auto node = rvsdg::TryGetOwnerNode<rvsdg::SimpleNode>(*user);
90 passThrough = passThrough && bufferOperation->IsPassThrough();
91 capacity = std::max(capacity, bufferOperation->Capacity());
92 auto bufOut = BufferOperation::create(*node->input(0)->origin(), capacity, passThrough)[0];
93 node->output(0)->divert_users(bufOut);
101 auto newOut = BufferOperation::create(*out, capacity, passThrough)[0];
102 directUser.divert_to(newOut);
142 bool outerLoop = !rvsdg::is<LoopOperation>(loopNode->
region()->
node());
146 for (
size_t i = 0; i < loopNode->
noutputs(); ++i)
148 auto out = loopNode->
output(i);
150 auto [branchNode, branchOperation] =
151 rvsdg::TryGetSimpleNodeAndOptionalOp<BranchOperation>(*res->origin());
152 if (!branchOperation)
158 auto oldBufInput = &branchNode->output(1)->SingleUser();
159 auto [oldBufferNode, oldBufferOperation] =
160 rvsdg::TryGetSimpleNodeAndOptionalOp<BufferOperation>(*oldBufInput);
161 if (rvsdg::IsOwnerNodeOperation<SinkOperation>(*oldBufInput))
167 auto oldBufNode = rvsdg::TryGetOwnerNode<rvsdg::SimpleNode>(*oldBufInput);
170 branchNode->input(1)->origin(),
171 oldBufferOperation->Capacity(),
172 oldBufferOperation->IsPassThrough());
176 branchNode->input(0)->origin(),
177 oldBufferOperation->Capacity(),
178 oldBufferOperation->IsPassThrough());
180 oldBufNode->output(0)->divert_users(oldBufInput->origin());
188 for (
size_t i = 0; i < loopNode->
ninputs(); ++i)
190 auto in = loopNode->
input(i);
192 auto user = &arg->SingleUser();
194 if (
auto [node, muxOperation] = rvsdg::TryGetSimpleNodeAndOptionalOp<MuxOperation>(*user);
197 if (!muxOperation->loop)
203 else if (rvsdg::IsOwnerNodeOperation<LoopConstantBufferOperation>(*user))
409 std::unordered_map<rvsdg::Output *, size_t> & output_cycles,
410 std::unordered_set<rvsdg::Input *> & frontier,
411 std::unordered_set<rvsdg::Input *> & stream_backedges,
412 std::unordered_set<rvsdg::SimpleNode *> & top_muxes)
414 for (
size_t i = 0; i < loop->
ninputs(); ++i)
416 auto in = loop->
input(i);
419 auto user = &arg->SingleUser();
420 auto userNode = rvsdg::TryGetOwnerNode<rvsdg::SimpleNode>(*user);
421 auto [muxNode, muxOperation] = rvsdg::TryGetSimpleNodeAndOptionalOp<MuxOperation>(*user);
422 if (rvsdg::IsOwnerNodeOperation<LoopConstantBufferOperation>(*user)
423 || (muxOperation && muxOperation->loop))
425 top_muxes.insert(userNode);
427 auto out = userNode->output(0);
428 output_cycles[out] = output_cycles[in->origin()];
429 frontier.insert(&out->SingleUser());
432 output_cycles[arg] = output_cycles[in->origin()];
433 frontier.insert(&arg->SingleUser());
438 auto out = tn.output(0);
439 output_cycles[out] = 0;
440 frontier.insert(&out->SingleUser());
445 auto backedge = std::get_if<LoopNode::BackEdgeVar>(&var);
450 auto user = &arg->SingleUser();
451 auto [muxNode, muxOperation] = rvsdg::TryGetSimpleNodeAndOptionalOp<MuxOperation>(*user);
452 if ((muxOperation && muxOperation->loop))
456 if (rvsdg::IsOwnerNodeOperation<BufferOperation>(*user))
458 auto bufNode = rvsdg::TryGetOwnerNode<rvsdg::SimpleNode>(*user);
459 if (rvsdg::IsOwnerNodeOperation<PredicateBufferOperation>(bufNode->output(0)->SingleUser()))
466 output_cycles[arg] = 0;
467 frontier.insert(&arg->SingleUser());
468 stream_backedges.insert(backedge->post);
480 std::unordered_map<rvsdg::Output *, size_t> & output_cycles,
481 std::unordered_set<rvsdg::Input *> & frontier,
482 std::unordered_set<rvsdg::Input *> & stream_backedges,
483 std::unordered_set<rvsdg::SimpleNode *> & top_muxes)
485 bool changed =
false;
489 for (
auto in : frontier)
491 bool inner_break =
false;
496 rvsdg::MatchTypeOrFail(
498 [&](rvsdg::SimpleNode & simpleNode)
500 bool all_contained = true;
501 for (auto & input : simpleNode.Inputs())
503 auto f = frontier.find(&input);
504 if (f == frontier.end())
506 all_contained = false;
512 std::vector<size_t> input_cycles;
513 for (auto & input : simpleNode.Inputs())
515 input_cycles.push_back(output_cycles[input.origin()]);
516 frontier.erase(&input);
518 std::vector<size_t> out_cycles = NodeCycles(&simpleNode, input_cycles);
520 if (top_muxes.find(&simpleNode) != top_muxes.end())
522 if (dynamic_cast<const MuxOperation *>(&simpleNode.GetOperation()))
527 auto pred_latency = output_cycles[simpleNode.input(0)->origin()];
528 auto input_latency = output_cycles[simpleNode.input(1)->origin()];
529 auto backedge_latency = output_cycles[simpleNode.input(2)->origin()];
530 auto out_latency = backedge_latency - pred_latency + input_latency;
531 std::cout <<
"top_mux " << &simpleNode <<
" pred latency: " << pred_latency
532 <<
" input latency: " << input_latency
533 <<
" backedge latency: " << backedge_latency
534 <<
" out latency: " << out_latency << std::endl;
535 output_cycles[simpleNode.output(0)] = out_latency;
540 rvsdg::is<LoopConstantBufferOperation>(simpleNode.GetOperation()));
546 for (size_t i = 0; i < simpleNode.noutputs(); ++i)
548 auto out = simpleNode.output(i);
549 output_cycles[out] = out_cycles[i];
550 frontier.insert(&out->SingleUser());
559 bool all_contained = true;
560 for (auto & input : inner_loop.Inputs())
562 auto f = frontier.find(&input);
563 if (f == frontier.end())
565 all_contained = false;
570 for (
auto & input : inner_loop.
Inputs())
572 frontier.erase(&input);
576 for (
size_t i = 0; i < inner_loop.
noutputs(); ++i)
578 std::cout <<
"output latency " << i <<
" "
579 << output_cycles[inner_loop.
output(i)] << std::endl;
589 rvsdg::MatchTypeOrFail(
595 [&](const LoopNode::BackEdgeVar & backedge)
598 auto out = backedge.pre;
599 if (stream_backedges.find(in) == stream_backedges.end())
602 output_cycles[out] = output_cycles[in->origin()];
603 frontier.insert(&out->SingleUser());
611 auto out = exit.output;
613 output_cycles[out] = output_cycles[in->origin()];
625 auto out = rr->output();
627 output_cycles[out] = output_cycles[in->origin()];
640 std::unordered_map<rvsdg::Output *, std::string> o_color;
641 std::unordered_map<rvsdg::Input *, std::string> i_color;
644 i_color.insert({ i,
"red" });
653 std::unordered_map<rvsdg::Output *, size_t> & output_cycles,
654 bool analyze_inner_loop)
656 if (!analyze_inner_loop)
658 for (
size_t i = 0; i < loop->
ninputs(); ++i)
660 auto in = loop->
input(i);
661 output_cycles[in->origin()] = 0;
664 std::unordered_set<rvsdg::Input *> frontier;
665 std::unordered_set<rvsdg::Input *> stream_backedges;
666 std::unordered_set<rvsdg::SimpleNode *> top_muxes;
668 std::unordered_set<rvsdg::Input *> frontier2(frontier);
669 std::cout <<
"CalculateLoopCycleDepth(" << loop <<
", " << analyze_inner_loop <<
")" << std::endl;
678 std::unordered_map<rvsdg::Output *, std::string> o_color;
679 std::unordered_map<rvsdg::Input *, std::string> i_color;
680 std::unordered_map<rvsdg::Output *, std::string> tail_label;
681 if (!analyze_inner_loop)
683 for (
auto i : frontier2)
685 i_color.insert({ i,
"red" });
687 for (
auto [o, l] : output_cycles)
689 tail_label[o] = std::to_string(l);
692 std::cout <<
"second iteration" << std::endl;
694 if (!analyze_inner_loop)
696 for (
auto [o, l] : output_cycles)
698 tail_label[o] = std::to_string(l);
716 JLM_ASSERT(!is_constant(rvsdg::TryGetOwnerNode<rvsdg::SimpleNode>(*out)));
717 auto [forkNode, forkOperation] = rvsdg::TryGetSimpleNodeAndOptionalOp<ForkOperation>(*out);
718 JLM_ASSERT(!(forkOperation && forkOperation->IsConstant()));
720 if (rvsdg::is<rvsdg::LambdaOperation>(out->
region()->
node()))
727 if (arg && arg->input())
729 return PlaceBufferLoop(arg->input()->origin(), min_capacity, passThrough);
733 if (
auto [loopConstantNode, op] =
734 rvsdg::TryGetSimpleNodeAndOptionalOp<LoopConstantBufferOperation>(*out);
738 PlaceBufferLoop(loopConstantNode->input(0)->origin(), min_capacity, passThrough),
739 PlaceBufferLoop(loopConstantNode->input(1)->origin(), min_capacity, passThrough));
742 if (
auto [node, bufferOperation] = rvsdg::TryGetSimpleNodeAndOptionalOp<BufferOperation>(*out);
746 passThrough = passThrough && bufferOperation->IsPassThrough();
747 size_t capacity =
round_up_pow2(bufferOperation->Capacity() + min_capacity);
752 BufferOperation::create(*node->input(0)->origin(), actual_capacity, passThrough)[0];
753 node->output(0)->divert_users(bufOut);
766 auto newOut = BufferOperation::create(*out, actual_capacity, passThrough)[0];
767 directUser.divert_to(newOut);
775 std::unordered_map<rvsdg::Output *, size_t> & output_cycles,
776 std::unordered_map<rvsdg::Output *, size_t> & buffer_capacity,
777 bool analyze_inner_loop =
false)
779 if (!analyze_inner_loop)
781 for (
size_t i = 0; i < loop->
ninputs(); ++i)
783 auto in = loop->
input(i);
784 buffer_capacity[in->origin()] = 0;
787 std::unordered_set<rvsdg::Input *> frontier;
788 std::unordered_set<rvsdg::Input *> stream_backedges;
789 std::unordered_set<rvsdg::SimpleNode *> top_muxes;
794 auto out = tn.output(0);
799 for (
size_t i = 0; i < loop->
ninputs(); ++i)
801 auto in = loop->
input(i);
808 std::unordered_map<rvsdg::Output *, std::string> o_color;
809 std::unordered_map<rvsdg::Input *, std::string> i_color;
810 std::unordered_map<rvsdg::Output *, std::string> tail_label;
811 if (!analyze_inner_loop)
813 for (
auto i : frontier)
815 i_color.insert({ i,
"red" });
817 for (
auto [o, l] : buffer_capacity)
819 tail_label[o] = std::to_string(l);
823 bool changed =
false;
827 for (
auto in : frontier)
829 bool inner_break =
false;
835 rvsdg::MatchTypeOrFail(
837 [&](rvsdg::SimpleNode & simpleNode)
839 bool all_contained = true;
840 for (auto & input : simpleNode.Inputs())
842 auto f = frontier.find(&input);
843 if (f == frontier.end())
845 all_contained = false;
851 size_t max_cycles = 0;
852 for (auto & input : simpleNode.Inputs())
854 max_cycles = std::max(max_cycles, output_cycles[input.origin()]);
855 frontier.erase(&input);
858 std::vector<size_t> input_capacities;
860 for (auto & input : simpleNode.Inputs())
862 auto capacity = buffer_capacity[input.origin()];
863 if (!analyze_inner_loop && (!rvsdg::is<AddressQueueOperation>(&simpleNode))
864 && capacity < max_cycles)
866 size_t capacity_diff = max_cycles - capacity;
867 capacity += PlaceBufferLoop(input.origin(), capacity_diff, true);
868 buffer_capacity[input.origin()] = capacity;
870 input_capacities.push_back(capacity);
873 if (top_muxes.find(&simpleNode) != top_muxes.end())
876 auto mux = dynamic_cast<const MuxOperation *>(&simpleNode.GetOperation());
879 std::cout <<
"top_mux " << &simpleNode <<
" pred capacity: "
880 << buffer_capacity[simpleNode.input(0)->origin()]
881 <<
" backedge capacity: "
882 << buffer_capacity[simpleNode.input(2)->origin()] << std::endl;
887 std::vector<size_t> out_capacities =
888 NodeCapacity(&simpleNode, input_capacities);
889 for (size_t i = 0; i < simpleNode.noutputs(); ++i)
891 auto out = simpleNode.output(i);
892 buffer_capacity[out] = out_capacities[i];
894 analyze_inner_loop || buffer_capacity[out] >= output_cycles[out]);
895 frontier.insert(&out->SingleUser());
904 bool all_contained = true;
905 for (auto & input : inner_loop.Inputs())
907 auto f = frontier.find(&input);
908 if (f == frontier.end())
910 all_contained = false;
916 size_t max_cycles = 0;
917 for (
auto & input : inner_loop.
Inputs())
919 max_cycles = std::max(max_cycles, output_cycles[input.origin()]);
920 frontier.erase(&input);
923 for (
size_t i = 0; i < inner_loop.
ninputs(); ++i)
925 auto capacity = buffer_capacity[inner_loop.
input(i)->
origin()];
926 if (!analyze_inner_loop && capacity < max_cycles)
929 auto [muxNode, muxOperation] =
930 rvsdg::TryGetSimpleNodeAndOptionalOp<MuxOperation>(*user);
931 if ((muxOperation && muxOperation->loop)
932 || rvsdg::IsOwnerNodeOperation<LoopConstantBufferOperation>(*user))
934 size_t capacity_diff = max_cycles - capacity;
937 buffer_capacity[inner_loop.
input(i)->
origin()] = capacity;
947 for (
size_t i = 0; i < inner_loop.
noutputs(); ++i)
958 rvsdg::MatchTypeOrFail(
964 [&](const LoopNode::BackEdgeVar & backedge)
967 auto out = backedge.pre;
968 buffer_capacity[out] = buffer_capacity[in->origin()];
969 if (stream_backedges.find(in) == stream_backedges.end())
971 frontier.insert(&out->SingleUser());
979 auto out = exit.output;
981 buffer_capacity[out] = buffer_capacity[in->origin()];
994 auto out = rr->output();
996 buffer_capacity[out] = buffer_capacity[in->origin()];
1016 if (!analyze_inner_loop)
1018 for (
auto [o, l] : buffer_capacity)
1020 tail_label[o] = std::to_string(l);