basic_block.cpp 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. // Copyright 2021 yuzu Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <algorithm>
  5. #include <initializer_list>
  6. #include <map>
  7. #include <memory>
  8. #include "common/bit_cast.h"
  9. #include "common/common_types.h"
  10. #include "shader_recompiler/frontend/ir/basic_block.h"
  11. #include "shader_recompiler/frontend/ir/value.h"
  12. namespace Shader::IR {
  13. Block::Block(ObjectPool<Inst>& inst_pool_) : inst_pool{&inst_pool_} {}
  14. Block::~Block() = default;
  15. void Block::AppendNewInst(Opcode op, std::initializer_list<Value> args) {
  16. PrependNewInst(end(), op, args);
  17. }
  18. Block::iterator Block::PrependNewInst(iterator insertion_point, const Inst& base_inst) {
  19. Inst* const inst{inst_pool->Create(base_inst)};
  20. return instructions.insert(insertion_point, *inst);
  21. }
  22. Block::iterator Block::PrependNewInst(iterator insertion_point, Opcode op,
  23. std::initializer_list<Value> args, u32 flags) {
  24. Inst* const inst{inst_pool->Create(op, flags)};
  25. const auto result_it{instructions.insert(insertion_point, *inst)};
  26. if (inst->NumArgs() != args.size()) {
  27. throw InvalidArgument("Invalid number of arguments {} in {}", args.size(), op);
  28. }
  29. std::ranges::for_each(args, [inst, index = size_t{0}](const Value& arg) mutable {
  30. inst->SetArg(index, arg);
  31. ++index;
  32. });
  33. return result_it;
  34. }
  35. void Block::AddBranch(Block* block) {
  36. if (std::ranges::find(imm_successors, block) != imm_successors.end()) {
  37. throw LogicError("Successor already inserted");
  38. }
  39. if (std::ranges::find(block->imm_predecessors, this) != block->imm_predecessors.end()) {
  40. throw LogicError("Predecessor already inserted");
  41. }
  42. imm_successors.push_back(block);
  43. block->imm_predecessors.push_back(this);
  44. }
  45. static std::string BlockToIndex(const std::map<const Block*, size_t>& block_to_index,
  46. Block* block) {
  47. if (const auto it{block_to_index.find(block)}; it != block_to_index.end()) {
  48. return fmt::format("{{Block ${}}}", it->second);
  49. }
  50. return fmt::format("$<unknown block {:016x}>", reinterpret_cast<u64>(block));
  51. }
  52. static size_t InstIndex(std::map<const Inst*, size_t>& inst_to_index, size_t& inst_index,
  53. const Inst* inst) {
  54. const auto [it, is_inserted]{inst_to_index.emplace(inst, inst_index + 1)};
  55. if (is_inserted) {
  56. ++inst_index;
  57. }
  58. return it->second;
  59. }
  60. static std::string ArgToIndex(std::map<const Inst*, size_t>& inst_to_index, size_t& inst_index,
  61. const Value& arg) {
  62. if (arg.IsEmpty()) {
  63. return "<null>";
  64. }
  65. if (!arg.IsImmediate() || arg.IsIdentity()) {
  66. return fmt::format("%{}", InstIndex(inst_to_index, inst_index, arg.Inst()));
  67. }
  68. switch (arg.Type()) {
  69. case Type::U1:
  70. return fmt::format("#{}", arg.U1() ? "true" : "false");
  71. case Type::U8:
  72. return fmt::format("#{}", arg.U8());
  73. case Type::U16:
  74. return fmt::format("#{}", arg.U16());
  75. case Type::U32:
  76. return fmt::format("#{}", arg.U32());
  77. case Type::U64:
  78. return fmt::format("#{}", arg.U64());
  79. case Type::F32:
  80. return fmt::format("#{}", arg.F32());
  81. case Type::Reg:
  82. return fmt::format("{}", arg.Reg());
  83. case Type::Pred:
  84. return fmt::format("{}", arg.Pred());
  85. case Type::Attribute:
  86. return fmt::format("{}", arg.Attribute());
  87. default:
  88. return "<unknown immediate type>";
  89. }
  90. }
  91. std::string DumpBlock(const Block& block) {
  92. size_t inst_index{0};
  93. std::map<const Inst*, size_t> inst_to_index;
  94. return DumpBlock(block, {}, inst_to_index, inst_index);
  95. }
  96. std::string DumpBlock(const Block& block, const std::map<const Block*, size_t>& block_to_index,
  97. std::map<const Inst*, size_t>& inst_to_index, size_t& inst_index) {
  98. std::string ret{"Block"};
  99. if (const auto it{block_to_index.find(&block)}; it != block_to_index.end()) {
  100. ret += fmt::format(" ${}", it->second);
  101. }
  102. ret += '\n';
  103. for (const Inst& inst : block) {
  104. const Opcode op{inst.GetOpcode()};
  105. ret += fmt::format("[{:016x}] ", reinterpret_cast<u64>(&inst));
  106. if (TypeOf(op) != Type::Void) {
  107. ret += fmt::format("%{:<5} = {}", InstIndex(inst_to_index, inst_index, &inst), op);
  108. } else {
  109. ret += fmt::format(" {}", op); // '%00000 = ' -> 1 + 5 + 3 = 9 spaces
  110. }
  111. const size_t arg_count{inst.NumArgs()};
  112. for (size_t arg_index = 0; arg_index < arg_count; ++arg_index) {
  113. const Value arg{inst.Arg(arg_index)};
  114. const std::string arg_str{ArgToIndex(inst_to_index, inst_index, arg)};
  115. ret += arg_index != 0 ? ", " : " ";
  116. if (op == Opcode::Phi) {
  117. ret += fmt::format("[ {}, {} ]", arg_str,
  118. BlockToIndex(block_to_index, inst.PhiBlock(arg_index)));
  119. } else {
  120. ret += arg_str;
  121. }
  122. if (op != Opcode::Phi) {
  123. const Type actual_type{arg.Type()};
  124. const Type expected_type{ArgTypeOf(op, arg_index)};
  125. if (!AreTypesCompatible(actual_type, expected_type)) {
  126. ret += fmt::format("<type error: {} != {}>", actual_type, expected_type);
  127. }
  128. }
  129. }
  130. if (TypeOf(op) != Type::Void) {
  131. ret += fmt::format(" (uses: {})\n", inst.UseCount());
  132. } else {
  133. ret += '\n';
  134. }
  135. }
  136. return ret;
  137. }
  138. } // namespace Shader::IR