breadth_first_search.h 1.8 KB

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