control_flow.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509
  1. // Copyright 2019 yuzu Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <list>
  5. #include <map>
  6. #include <unordered_map>
  7. #include <unordered_set>
  8. #include <vector>
  9. #include "common/assert.h"
  10. #include "common/common_types.h"
  11. #include "video_core/shader/control_flow.h"
  12. #include "video_core/shader/shader_ir.h"
  13. namespace VideoCommon::Shader {
  14. using Tegra::Shader::Instruction;
  15. using Tegra::Shader::OpCode;
  16. constexpr s32 unassigned_branch = -2;
  17. /***
  18. * 'ControlStack' represents a static stack of control jumps such as SSY and PBK
  19. * stacks in Maxwell.
  20. ***/
  21. struct ControlStack {
  22. static constexpr std::size_t stack_fixed_size = 20;
  23. std::array<u32, stack_fixed_size> stack{};
  24. u32 index{};
  25. bool Compare(const ControlStack& cs) const {
  26. if (index != cs.index) {
  27. return false;
  28. }
  29. return std::memcmp(stack.data(), cs.stack.data(), index * sizeof(u32)) == 0;
  30. }
  31. /// This compare just compares the top of the stack against one another
  32. bool SoftCompare(const ControlStack& cs) const {
  33. if (index == 0 || cs.index == 0) {
  34. return index == cs.index;
  35. }
  36. return Top() == cs.Top();
  37. }
  38. u32 Size() const {
  39. return index;
  40. }
  41. u32 Top() const {
  42. return stack[index - 1];
  43. }
  44. bool Push(u32 address) {
  45. if (index >= stack.size()) {
  46. return false;
  47. }
  48. stack[index] = address;
  49. index++;
  50. return true;
  51. }
  52. bool Pop() {
  53. if (index == 0) {
  54. return false;
  55. }
  56. index--;
  57. return true;
  58. }
  59. };
  60. struct Query {
  61. u32 address{};
  62. ControlStack ssy_stack{};
  63. ControlStack pbk_stack{};
  64. };
  65. struct BlockStack {
  66. BlockStack() = default;
  67. BlockStack(const BlockStack& b) = default;
  68. BlockStack(const Query& q) : ssy_stack{q.ssy_stack}, pbk_stack{q.pbk_stack} {}
  69. ControlStack ssy_stack{};
  70. ControlStack pbk_stack{};
  71. };
  72. struct BlockBranchInfo {
  73. Condition condition{};
  74. s32 address{exit_branch};
  75. bool kill{};
  76. bool is_sync{};
  77. bool is_brk{};
  78. bool ignore{};
  79. };
  80. struct BlockInfo {
  81. u32 start{};
  82. u32 end{};
  83. bool visited{};
  84. BlockBranchInfo branch{};
  85. bool IsInside(const u32 address) const {
  86. return start <= address && address <= end;
  87. }
  88. };
  89. struct CFGRebuildState {
  90. explicit CFGRebuildState(const ProgramCode& program_code, const std::size_t program_size)
  91. : program_code{program_code}, program_size{program_size} {}
  92. std::vector<BlockInfo> block_info{};
  93. std::list<u32> inspect_queries{};
  94. std::list<Query> queries{};
  95. std::unordered_map<u32, u32> registered{};
  96. std::unordered_set<u32> labels{};
  97. std::map<u32, u32> ssy_labels{};
  98. std::map<u32, u32> pbk_labels{};
  99. std::unordered_map<u32, BlockStack> stacks{};
  100. const ProgramCode& program_code;
  101. const std::size_t program_size;
  102. };
  103. enum class BlockCollision : u32 { None = 0, Found = 1, Inside = 2 };
  104. std::pair<BlockCollision, std::vector<BlockInfo>::iterator> TryGetBlock(CFGRebuildState& state,
  105. u32 address) {
  106. auto it = state.block_info.begin();
  107. while (it != state.block_info.end()) {
  108. if (it->start == address) {
  109. return {BlockCollision::Found, it};
  110. }
  111. if (it->IsInside(address)) {
  112. return {BlockCollision::Inside, it};
  113. }
  114. it++;
  115. }
  116. return {BlockCollision::None, it};
  117. }
  118. struct ParseInfo {
  119. BlockBranchInfo branch_info{};
  120. u32 end_address{};
  121. };
  122. BlockInfo* CreateBlockInfo(CFGRebuildState& state, u32 start, u32 end) {
  123. auto& it = state.block_info.emplace_back();
  124. it.start = start;
  125. it.end = end;
  126. const u32 index = static_cast<u32>(state.block_info.size() - 1);
  127. state.registered.insert({start, index});
  128. return &it;
  129. }
  130. Pred GetPredicate(u32 index, bool negated) {
  131. return static_cast<Pred>(index + (negated ? 8 : 0));
  132. }
  133. enum class ParseResult : u32 {
  134. ControlCaught = 0,
  135. BlockEnd = 1,
  136. AbnormalFlow = 2,
  137. };
  138. ParseResult ParseCode(CFGRebuildState& state, u32 address, ParseInfo& parse_info) {
  139. u32 offset = static_cast<u32>(address);
  140. const u32 end_address = static_cast<u32>(state.program_size - 10U) * 8U;
  141. const auto insert_label = ([](CFGRebuildState& state, u32 address) {
  142. auto pair = state.labels.emplace(address);
  143. if (pair.second) {
  144. state.inspect_queries.push_back(address);
  145. }
  146. });
  147. while (true) {
  148. if (offset >= end_address) {
  149. parse_info.branch_info.address = exit_branch;
  150. parse_info.branch_info.ignore = false;
  151. break;
  152. }
  153. if (state.registered.count(offset) != 0) {
  154. parse_info.branch_info.address = offset;
  155. parse_info.branch_info.ignore = true;
  156. break;
  157. }
  158. const Instruction instr = {state.program_code[offset]};
  159. const auto opcode = OpCode::Decode(instr);
  160. if (!opcode || opcode->get().GetType() != OpCode::Type::Flow) {
  161. offset++;
  162. continue;
  163. }
  164. switch (opcode->get().GetId()) {
  165. case OpCode::Id::EXIT: {
  166. const auto pred_index = static_cast<u32>(instr.pred.pred_index);
  167. parse_info.branch_info.condition.predicate =
  168. GetPredicate(pred_index, instr.negate_pred != 0);
  169. if (parse_info.branch_info.condition.predicate == Pred::NeverExecute) {
  170. offset++;
  171. continue;
  172. }
  173. const ConditionCode cc = instr.flow_condition_code;
  174. parse_info.branch_info.condition.cc = cc;
  175. if (cc == ConditionCode::F) {
  176. offset++;
  177. continue;
  178. }
  179. parse_info.branch_info.address = exit_branch;
  180. parse_info.branch_info.kill = false;
  181. parse_info.branch_info.is_sync = false;
  182. parse_info.branch_info.is_brk = false;
  183. parse_info.branch_info.ignore = false;
  184. parse_info.end_address = offset;
  185. return ParseResult::ControlCaught;
  186. }
  187. case OpCode::Id::BRA: {
  188. if (instr.bra.constant_buffer != 0) {
  189. return ParseResult::AbnormalFlow;
  190. }
  191. const auto pred_index = static_cast<u32>(instr.pred.pred_index);
  192. parse_info.branch_info.condition.predicate =
  193. GetPredicate(pred_index, instr.negate_pred != 0);
  194. if (parse_info.branch_info.condition.predicate == Pred::NeverExecute) {
  195. offset++;
  196. continue;
  197. }
  198. const ConditionCode cc = instr.flow_condition_code;
  199. parse_info.branch_info.condition.cc = cc;
  200. if (cc == ConditionCode::F) {
  201. offset++;
  202. continue;
  203. }
  204. u32 branch_offset = offset + instr.bra.GetBranchTarget();
  205. if (branch_offset == 0) {
  206. parse_info.branch_info.address = exit_branch;
  207. } else {
  208. parse_info.branch_info.address = branch_offset;
  209. }
  210. insert_label(state, branch_offset);
  211. parse_info.branch_info.kill = false;
  212. parse_info.branch_info.is_sync = false;
  213. parse_info.branch_info.is_brk = false;
  214. parse_info.branch_info.ignore = false;
  215. parse_info.end_address = offset;
  216. return ParseResult::ControlCaught;
  217. }
  218. case OpCode::Id::SYNC: {
  219. parse_info.branch_info.condition;
  220. const auto pred_index = static_cast<u32>(instr.pred.pred_index);
  221. parse_info.branch_info.condition.predicate =
  222. GetPredicate(pred_index, instr.negate_pred != 0);
  223. if (parse_info.branch_info.condition.predicate == Pred::NeverExecute) {
  224. offset++;
  225. continue;
  226. }
  227. const ConditionCode cc = instr.flow_condition_code;
  228. parse_info.branch_info.condition.cc = cc;
  229. if (cc == ConditionCode::F) {
  230. offset++;
  231. continue;
  232. }
  233. parse_info.branch_info.address = unassigned_branch;
  234. parse_info.branch_info.kill = false;
  235. parse_info.branch_info.is_sync = true;
  236. parse_info.branch_info.is_brk = false;
  237. parse_info.branch_info.ignore = false;
  238. parse_info.end_address = offset;
  239. return ParseResult::ControlCaught;
  240. }
  241. case OpCode::Id::BRK: {
  242. parse_info.branch_info.condition;
  243. const auto pred_index = static_cast<u32>(instr.pred.pred_index);
  244. parse_info.branch_info.condition.predicate =
  245. GetPredicate(pred_index, instr.negate_pred != 0);
  246. if (parse_info.branch_info.condition.predicate == Pred::NeverExecute) {
  247. offset++;
  248. continue;
  249. }
  250. const ConditionCode cc = instr.flow_condition_code;
  251. parse_info.branch_info.condition.cc = cc;
  252. if (cc == ConditionCode::F) {
  253. offset++;
  254. continue;
  255. }
  256. parse_info.branch_info.address = unassigned_branch;
  257. parse_info.branch_info.kill = false;
  258. parse_info.branch_info.is_sync = false;
  259. parse_info.branch_info.is_brk = true;
  260. parse_info.branch_info.ignore = false;
  261. parse_info.end_address = offset;
  262. return ParseResult::ControlCaught;
  263. }
  264. case OpCode::Id::KIL: {
  265. parse_info.branch_info.condition;
  266. const auto pred_index = static_cast<u32>(instr.pred.pred_index);
  267. parse_info.branch_info.condition.predicate =
  268. GetPredicate(pred_index, instr.negate_pred != 0);
  269. if (parse_info.branch_info.condition.predicate == Pred::NeverExecute) {
  270. offset++;
  271. continue;
  272. }
  273. const ConditionCode cc = instr.flow_condition_code;
  274. parse_info.branch_info.condition.cc = cc;
  275. if (cc == ConditionCode::F) {
  276. offset++;
  277. continue;
  278. }
  279. parse_info.branch_info.address = exit_branch;
  280. parse_info.branch_info.kill = true;
  281. parse_info.branch_info.is_sync = false;
  282. parse_info.branch_info.is_brk = false;
  283. parse_info.branch_info.ignore = false;
  284. parse_info.end_address = offset;
  285. return ParseResult::ControlCaught;
  286. }
  287. case OpCode::Id::SSY: {
  288. const u32 target = offset + instr.bra.GetBranchTarget();
  289. insert_label(state, target);
  290. state.ssy_labels.emplace(offset, target);
  291. break;
  292. }
  293. case OpCode::Id::PBK: {
  294. const u32 target = offset + instr.bra.GetBranchTarget();
  295. insert_label(state, target);
  296. state.pbk_labels.emplace(offset, target);
  297. break;
  298. }
  299. case OpCode::Id::BRX: {
  300. return ParseResult::AbnormalFlow;
  301. }
  302. default:
  303. break;
  304. }
  305. offset++;
  306. }
  307. parse_info.branch_info.kill = false;
  308. parse_info.branch_info.is_sync = false;
  309. parse_info.branch_info.is_brk = false;
  310. parse_info.end_address = offset - 1;
  311. return ParseResult::BlockEnd;
  312. }
  313. bool TryInspectAddress(CFGRebuildState& state) {
  314. if (state.inspect_queries.empty()) {
  315. return false;
  316. }
  317. const u32 address = state.inspect_queries.front();
  318. state.inspect_queries.pop_front();
  319. const auto search_result = TryGetBlock(state, address);
  320. switch (search_result.first) {
  321. case BlockCollision::Found: {
  322. return true;
  323. }
  324. case BlockCollision::Inside: {
  325. // This case is the tricky one:
  326. // We need to Split the block in 2 sepparate blocks
  327. auto it = search_result.second;
  328. BlockInfo* block_info = CreateBlockInfo(state, address, it->end);
  329. it->end = address - 1;
  330. block_info->branch = it->branch;
  331. BlockBranchInfo forward_branch{};
  332. forward_branch.address = address;
  333. forward_branch.ignore = true;
  334. it->branch = forward_branch;
  335. return true;
  336. }
  337. default:
  338. break;
  339. }
  340. ParseInfo parse_info;
  341. const ParseResult parse_result = ParseCode(state, address, parse_info);
  342. if (parse_result == ParseResult::AbnormalFlow) {
  343. // if it's AbnormalFlow, we end it as false, ending the CFG reconstruction
  344. return false;
  345. }
  346. BlockInfo* block_info = CreateBlockInfo(state, address, parse_info.end_address);
  347. block_info->branch = parse_info.branch_info;
  348. if (parse_info.branch_info.condition.IsUnconditional()) {
  349. return true;
  350. }
  351. const u32 fallthrough_address = parse_info.end_address + 1;
  352. state.inspect_queries.push_front(fallthrough_address);
  353. return true;
  354. }
  355. bool TryQuery(CFGRebuildState& state) {
  356. const auto gather_labels = ([](ControlStack& cc, std::map<u32, u32>& labels, BlockInfo& block) {
  357. auto gather_start = labels.lower_bound(block.start);
  358. const auto gather_end = labels.upper_bound(block.end);
  359. while (gather_start != gather_end) {
  360. cc.Push(gather_start->second);
  361. gather_start++;
  362. }
  363. });
  364. if (state.queries.empty()) {
  365. return false;
  366. }
  367. Query& q = state.queries.front();
  368. const u32 block_index = state.registered[q.address];
  369. BlockInfo& block = state.block_info[block_index];
  370. // If the block is visted, check if the stacks match, else gather the ssy/pbk
  371. // labels into the current stack and look if the branch at the end of the block
  372. // consumes a label. Schedule new queries accordingly
  373. if (block.visited) {
  374. BlockStack& stack = state.stacks[q.address];
  375. const bool all_okay =
  376. (stack.ssy_stack.Size() == 0 || q.ssy_stack.Compare(stack.ssy_stack)) &&
  377. (stack.pbk_stack.Size() == 0 || q.pbk_stack.Compare(stack.pbk_stack));
  378. state.queries.pop_front();
  379. return all_okay;
  380. }
  381. block.visited = true;
  382. state.stacks[q.address] = BlockStack{q};
  383. Query q2(q);
  384. state.queries.pop_front();
  385. gather_labels(q2.ssy_stack, state.ssy_labels, block);
  386. gather_labels(q2.pbk_stack, state.pbk_labels, block);
  387. if (!block.branch.condition.IsUnconditional()) {
  388. q2.address = block.end + 1;
  389. state.queries.push_back(q2);
  390. }
  391. Query conditional_query{q2};
  392. if (block.branch.is_sync) {
  393. if (block.branch.address == unassigned_branch) {
  394. block.branch.address = conditional_query.ssy_stack.Top();
  395. }
  396. conditional_query.ssy_stack.Pop();
  397. }
  398. if (block.branch.is_brk) {
  399. if (block.branch.address == unassigned_branch) {
  400. block.branch.address = conditional_query.pbk_stack.Top();
  401. }
  402. conditional_query.pbk_stack.Pop();
  403. }
  404. conditional_query.address = block.branch.address;
  405. state.queries.push_back(conditional_query);
  406. return true;
  407. }
  408. std::optional<ShaderCharacteristics> ScanFlow(const ProgramCode& program_code, u32 program_size,
  409. u32 start_address) {
  410. CFGRebuildState state{program_code, program_size};
  411. // Inspect Code and generate blocks
  412. state.labels.clear();
  413. state.labels.emplace(start_address);
  414. state.inspect_queries.push_back(start_address);
  415. while (!state.inspect_queries.empty()) {
  416. if (!TryInspectAddress(state)) {
  417. return {};
  418. }
  419. }
  420. // Decompile Stacks
  421. Query start_query{};
  422. start_query.address = start_address;
  423. state.queries.push_back(start_query);
  424. bool decompiled = true;
  425. while (!state.queries.empty()) {
  426. if (!TryQuery(state)) {
  427. decompiled = false;
  428. break;
  429. }
  430. }
  431. // Sort and organize results
  432. std::sort(state.block_info.begin(), state.block_info.end(),
  433. [](const BlockInfo& a, const BlockInfo& b) -> bool { return a.start < b.start; });
  434. ShaderCharacteristics result_out{};
  435. result_out.decompilable = decompiled;
  436. result_out.start = start_address;
  437. result_out.end = start_address;
  438. for (auto& block : state.block_info) {
  439. ShaderBlock new_block{};
  440. new_block.start = block.start;
  441. new_block.end = block.end;
  442. new_block.ignore_branch = block.branch.ignore;
  443. if (!new_block.ignore_branch) {
  444. new_block.branch.cond = block.branch.condition;
  445. new_block.branch.kills = block.branch.kill;
  446. new_block.branch.address = block.branch.address;
  447. }
  448. result_out.end = std::max(result_out.end, block.end);
  449. result_out.blocks.push_back(new_block);
  450. }
  451. if (result_out.decompilable) {
  452. result_out.labels = std::move(state.labels);
  453. return {result_out};
  454. }
  455. // If it's not decompilable, merge the unlabelled blocks together
  456. auto back = result_out.blocks.begin();
  457. auto next = std::next(back);
  458. while (next != result_out.blocks.end()) {
  459. if (state.labels.count(next->start) == 0 && next->start == back->end + 1) {
  460. back->end = next->end;
  461. next = result_out.blocks.erase(next);
  462. continue;
  463. }
  464. back = next;
  465. next++;
  466. }
  467. return {result_out};
  468. }
  469. } // namespace VideoCommon::Shader