breadth_first_search.h 1.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455
  1. // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #pragma once
  4. #include <optional>
  5. #include <type_traits>
  6. #include <queue>
  7. #include <boost/container/small_vector.hpp>
  8. #include "shader_recompiler/frontend/ir/value.h"
  9. namespace Shader::IR {
  10. template <typename Pred>
  11. auto BreadthFirstSearch(const Value& value, Pred&& pred)
  12. -> std::invoke_result_t<Pred, const Inst*> {
  13. if (value.IsImmediate()) {
  14. // Nothing to do with immediates
  15. return std::nullopt;
  16. }
  17. // Breadth-first search visiting the right most arguments first
  18. // Small vector has been determined from shaders in Super Smash Bros. Ultimate
  19. boost::container::small_vector<const Inst*, 2> visited;
  20. std::queue<const Inst*> queue;
  21. queue.push(value.InstRecursive());
  22. while (!queue.empty()) {
  23. // Pop one instruction from the queue
  24. const Inst* const inst{queue.front()};
  25. queue.pop();
  26. if (const std::optional result = pred(inst)) {
  27. // This is the instruction we were looking for
  28. return result;
  29. }
  30. // Visit the right most arguments first
  31. for (size_t arg = inst->NumArgs(); arg--;) {
  32. const Value arg_value{inst->Arg(arg)};
  33. if (arg_value.IsImmediate()) {
  34. continue;
  35. }
  36. // Queue instruction if it hasn't been visited
  37. const Inst* const arg_inst{arg_value.InstRecursive()};
  38. if (std::ranges::find(visited, arg_inst) == visited.end()) {
  39. visited.push_back(arg_inst);
  40. queue.push(arg_inst);
  41. }
  42. }
  43. }
  44. // SSA tree has been traversed and the result hasn't been found
  45. return std::nullopt;
  46. }
  47. } // namespace Shader::IR