decode.cpp 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. // Copyright 2018 yuzu Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <cstring>
  5. #include <set>
  6. #include <fmt/format.h>
  7. #include "common/assert.h"
  8. #include "common/common_types.h"
  9. #include "video_core/engines/shader_bytecode.h"
  10. #include "video_core/engines/shader_header.h"
  11. #include "video_core/shader/control_flow.h"
  12. #include "video_core/shader/node_helper.h"
  13. #include "video_core/shader/shader_ir.h"
  14. namespace VideoCommon::Shader {
  15. using Tegra::Shader::Instruction;
  16. using Tegra::Shader::OpCode;
  17. namespace {
  18. /**
  19. * Returns whether the instruction at the specified offset is a 'sched' instruction.
  20. * Sched instructions always appear before a sequence of 3 instructions.
  21. */
  22. constexpr bool IsSchedInstruction(u32 offset, u32 main_offset) {
  23. constexpr u32 SchedPeriod = 4;
  24. u32 absolute_offset = offset - main_offset;
  25. return (absolute_offset % SchedPeriod) == 0;
  26. }
  27. } // namespace
  28. void ShaderIR::Decode() {
  29. std::memcpy(&header, program_code.data(), sizeof(Tegra::Shader::Header));
  30. disable_flow_stack = false;
  31. const auto info = ScanFlow(program_code, program_size, main_offset);
  32. if (info) {
  33. const auto& shader_info = *info;
  34. coverage_begin = shader_info.start;
  35. coverage_end = shader_info.end;
  36. if (shader_info.decompilable) {
  37. disable_flow_stack = true;
  38. const auto insert_block = ([this](NodeBlock& nodes, u32 label) {
  39. if (label == exit_branch) {
  40. return;
  41. }
  42. basic_blocks.insert({label, nodes});
  43. });
  44. const auto& blocks = shader_info.blocks;
  45. NodeBlock current_block;
  46. u32 current_label = exit_branch;
  47. for (auto& block : blocks) {
  48. if (shader_info.labels.count(block.start) != 0) {
  49. insert_block(current_block, current_label);
  50. current_block.clear();
  51. current_label = block.start;
  52. }
  53. if (!block.ignore_branch) {
  54. DecodeRangeInner(current_block, block.start, block.end);
  55. InsertControlFlow(current_block, block);
  56. } else {
  57. DecodeRangeInner(current_block, block.start, block.end + 1);
  58. }
  59. }
  60. insert_block(current_block, current_label);
  61. return;
  62. }
  63. LOG_WARNING(HW_GPU, "Flow Stack Removing Failed! Falling back to old method");
  64. // we can't decompile it, fallback to standard method
  65. for (const auto& block : shader_info.blocks) {
  66. basic_blocks.insert({block.start, DecodeRange(block.start, block.end + 1)});
  67. }
  68. return;
  69. }
  70. LOG_WARNING(HW_GPU, "Flow Analysis Failed! Falling back to brute force compiling");
  71. // Now we need to deal with an undecompilable shader. We need to brute force
  72. // a shader that captures every position.
  73. coverage_begin = main_offset;
  74. const u32 shader_end = static_cast<u32>(program_size / sizeof(u64));
  75. coverage_end = shader_end;
  76. for (u32 label = main_offset; label < shader_end; label++) {
  77. basic_blocks.insert({label, DecodeRange(label, label + 1)});
  78. }
  79. }
  80. NodeBlock ShaderIR::DecodeRange(u32 begin, u32 end) {
  81. NodeBlock basic_block;
  82. DecodeRangeInner(basic_block, begin, end);
  83. return basic_block;
  84. }
  85. void ShaderIR::DecodeRangeInner(NodeBlock& bb, u32 begin, u32 end) {
  86. for (u32 pc = begin; pc < (begin > end ? MAX_PROGRAM_LENGTH : end);) {
  87. pc = DecodeInstr(bb, pc);
  88. }
  89. }
  90. void ShaderIR::InsertControlFlow(NodeBlock& bb, const ShaderBlock& block) {
  91. const auto apply_conditions = ([&](const Condition& cond, Node n) -> Node {
  92. Node result = n;
  93. if (cond.cc != ConditionCode::T) {
  94. result = Conditional(GetConditionCode(cond.cc), {result});
  95. }
  96. if (cond.predicate != Pred::UnusedIndex) {
  97. u32 pred = static_cast<u32>(cond.predicate);
  98. const bool is_neg = pred > 7;
  99. if (is_neg) {
  100. pred -= 8;
  101. }
  102. result = Conditional(GetPredicate(pred, is_neg), {result});
  103. }
  104. return result;
  105. });
  106. if (block.branch.address < 0) {
  107. if (block.branch.kills) {
  108. Node n = Operation(OperationCode::Discard);
  109. n = apply_conditions(block.branch.cond, n);
  110. bb.push_back(n);
  111. global_code.push_back(n);
  112. return;
  113. }
  114. Node n = Operation(OperationCode::Exit);
  115. n = apply_conditions(block.branch.cond, n);
  116. bb.push_back(n);
  117. global_code.push_back(n);
  118. return;
  119. }
  120. Node n = Operation(OperationCode::Branch, Immediate(block.branch.address));
  121. n = apply_conditions(block.branch.cond, n);
  122. bb.push_back(n);
  123. global_code.push_back(n);
  124. }
  125. u32 ShaderIR::DecodeInstr(NodeBlock& bb, u32 pc) {
  126. // Ignore sched instructions when generating code.
  127. if (IsSchedInstruction(pc, main_offset)) {
  128. return pc + 1;
  129. }
  130. const Instruction instr = {program_code[pc]};
  131. const auto opcode = OpCode::Decode(instr);
  132. // Decoding failure
  133. if (!opcode) {
  134. UNIMPLEMENTED_MSG("Unhandled instruction: {0:x}", instr.value);
  135. return pc + 1;
  136. }
  137. bb.push_back(
  138. Comment(fmt::format("{}: {} (0x{:016x})", pc, opcode->get().GetName(), instr.value)));
  139. using Tegra::Shader::Pred;
  140. UNIMPLEMENTED_IF_MSG(instr.pred.full_pred == Pred::NeverExecute,
  141. "NeverExecute predicate not implemented");
  142. static const std::map<OpCode::Type, u32 (ShaderIR::*)(NodeBlock&, u32)> decoders = {
  143. {OpCode::Type::Arithmetic, &ShaderIR::DecodeArithmetic},
  144. {OpCode::Type::ArithmeticImmediate, &ShaderIR::DecodeArithmeticImmediate},
  145. {OpCode::Type::Bfe, &ShaderIR::DecodeBfe},
  146. {OpCode::Type::Bfi, &ShaderIR::DecodeBfi},
  147. {OpCode::Type::Shift, &ShaderIR::DecodeShift},
  148. {OpCode::Type::ArithmeticInteger, &ShaderIR::DecodeArithmeticInteger},
  149. {OpCode::Type::ArithmeticIntegerImmediate, &ShaderIR::DecodeArithmeticIntegerImmediate},
  150. {OpCode::Type::ArithmeticHalf, &ShaderIR::DecodeArithmeticHalf},
  151. {OpCode::Type::ArithmeticHalfImmediate, &ShaderIR::DecodeArithmeticHalfImmediate},
  152. {OpCode::Type::Ffma, &ShaderIR::DecodeFfma},
  153. {OpCode::Type::Hfma2, &ShaderIR::DecodeHfma2},
  154. {OpCode::Type::Conversion, &ShaderIR::DecodeConversion},
  155. {OpCode::Type::Memory, &ShaderIR::DecodeMemory},
  156. {OpCode::Type::Texture, &ShaderIR::DecodeTexture},
  157. {OpCode::Type::Image, &ShaderIR::DecodeImage},
  158. {OpCode::Type::FloatSetPredicate, &ShaderIR::DecodeFloatSetPredicate},
  159. {OpCode::Type::IntegerSetPredicate, &ShaderIR::DecodeIntegerSetPredicate},
  160. {OpCode::Type::HalfSetPredicate, &ShaderIR::DecodeHalfSetPredicate},
  161. {OpCode::Type::PredicateSetRegister, &ShaderIR::DecodePredicateSetRegister},
  162. {OpCode::Type::PredicateSetPredicate, &ShaderIR::DecodePredicateSetPredicate},
  163. {OpCode::Type::RegisterSetPredicate, &ShaderIR::DecodeRegisterSetPredicate},
  164. {OpCode::Type::FloatSet, &ShaderIR::DecodeFloatSet},
  165. {OpCode::Type::IntegerSet, &ShaderIR::DecodeIntegerSet},
  166. {OpCode::Type::HalfSet, &ShaderIR::DecodeHalfSet},
  167. {OpCode::Type::Video, &ShaderIR::DecodeVideo},
  168. {OpCode::Type::Xmad, &ShaderIR::DecodeXmad},
  169. };
  170. std::vector<Node> tmp_block;
  171. if (const auto decoder = decoders.find(opcode->get().GetType()); decoder != decoders.end()) {
  172. pc = (this->*decoder->second)(tmp_block, pc);
  173. } else {
  174. pc = DecodeOther(tmp_block, pc);
  175. }
  176. // Some instructions (like SSY) don't have a predicate field, they are always unconditionally
  177. // executed.
  178. const bool can_be_predicated = OpCode::IsPredicatedInstruction(opcode->get().GetId());
  179. const auto pred_index = static_cast<u32>(instr.pred.pred_index);
  180. if (can_be_predicated && pred_index != static_cast<u32>(Pred::UnusedIndex)) {
  181. const Node conditional =
  182. Conditional(GetPredicate(pred_index, instr.negate_pred != 0), std::move(tmp_block));
  183. global_code.push_back(conditional);
  184. bb.push_back(conditional);
  185. } else {
  186. for (auto& node : tmp_block) {
  187. global_code.push_back(node);
  188. bb.push_back(node);
  189. }
  190. }
  191. return pc + 1;
  192. }
  193. } // namespace VideoCommon::Shader