| 1479 | } |
| 1480 | |
| 1481 | void apply(module& m, const match::matcher_result& r) const |
| 1482 | { |
| 1483 | // Verifies that the slices meet several conditions: they must all output to the same |
| 1484 | // concat instruction, slice on the same (1 only) axis, and the end of one slice |
| 1485 | // must match the start of the next. |
| 1486 | auto ins = r.result; |
| 1487 | |
| 1488 | auto splits = get_splits(ins); |
| 1489 | if(splits.empty()) |
| 1490 | return; |
| 1491 | // Each slice must output to only one instruction |
| 1492 | if(std::any_of( |
| 1493 | splits.begin(), splits.end(), [](auto i) { return i->outputs().size() != 1; })) |
| 1494 | return; |
| 1495 | // The single output instruction for all items in the list must be the same one |
| 1496 | auto concat = splits.front()->outputs().front(); |
| 1497 | if(std::any_of(splits.begin(), splits.end(), [&](auto i) { |
| 1498 | return i->outputs().front() != concat; |
| 1499 | })) |
| 1500 | return; |
| 1501 | |
| 1502 | // The axis for the common output instruction must be the same as for the split ops |
| 1503 | auto concat_op = any_cast<op::concat>(concat->get_operator()); |
| 1504 | auto split_op = any_cast<op::slice>(splits.front()->get_operator()); |
| 1505 | if(split_op.axes.size() != 1) |
| 1506 | return; |
| 1507 | if(split_op.axes.front() != concat_op.axis) |
| 1508 | return; |
| 1509 | |
| 1510 | // Find where the slices are in the concat instruction's inputs (concat can have |
| 1511 | // any number of inputs) |
| 1512 | auto args = concat->inputs(); |
| 1513 | auto it = |
| 1514 | std::find_if(args.begin(), args.end(), [&](auto i) { return i == splits.front(); }); |
| 1515 | // Verify the slices were found, and the list is long enough |
| 1516 | if(std::distance(it, args.end()) < splits.size()) |
| 1517 | return; |
| 1518 | // Don't do anything if the "slice" inputs to the concat op have other operations mixed in |
| 1519 | // among them |
| 1520 | if(std::any_of(it, it + splits.size(), [](instruction_ref x) { |
| 1521 | return x->get_operator().name() != "slice"; |
| 1522 | })) |
| 1523 | return; |
| 1524 | // Check that the slices passed to concat are in order. |
| 1525 | if(not std::is_sorted(it, it + splits.size(), [](instruction_ref x, instruction_ref y) { |
| 1526 | auto xop = any_cast<op::slice>(x->get_operator()); |
| 1527 | auto yop = any_cast<op::slice>(y->get_operator()); |
| 1528 | return std::tie(xop.starts, xop.ends) < std::tie(yop.starts, yop.ends); |
| 1529 | })) |
| 1530 | return; |
| 1531 | |
| 1532 | // Perform the substitution |
| 1533 | *it = splits.front()->inputs().front(); |
| 1534 | args.erase(std::next(it), it + splits.size()); |
| 1535 | |
| 1536 | if(args.size() == 1) |
| 1537 | m.replace_instruction(concat, args.front()); |
| 1538 | else |
nothing calls this directly
no test coverage detected