control_flow.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749
  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 <set>
  7. #include <stack>
  8. #include <unordered_map>
  9. #include <vector>
  10. #include "common/assert.h"
  11. #include "common/common_types.h"
  12. #include "video_core/shader/ast.h"
  13. #include "video_core/shader/control_flow.h"
  14. #include "video_core/shader/shader_ir.h"
  15. namespace VideoCommon::Shader {
  16. namespace {
  17. using Tegra::Shader::Instruction;
  18. using Tegra::Shader::OpCode;
  19. constexpr s32 unassigned_branch = -2;
  20. struct Query {
  21. u32 address{};
  22. std::stack<u32> ssy_stack{};
  23. std::stack<u32> pbk_stack{};
  24. };
  25. struct BlockStack {
  26. BlockStack() = default;
  27. explicit BlockStack(const Query& q) : ssy_stack{q.ssy_stack}, pbk_stack{q.pbk_stack} {}
  28. std::stack<u32> ssy_stack{};
  29. std::stack<u32> pbk_stack{};
  30. };
  31. template <typename T, typename... Args>
  32. BlockBranchInfo MakeBranchInfo(Args&&... args) {
  33. static_assert(std::is_convertible_v<T, BranchData>);
  34. return std::make_shared<BranchData>(T(std::forward<Args>(args)...));
  35. }
  36. bool BlockBranchIsIgnored(BlockBranchInfo first) {
  37. bool ignore = false;
  38. if (std::holds_alternative<SingleBranch>(*first)) {
  39. const auto branch = std::get_if<SingleBranch>(first.get());
  40. ignore = branch->ignore;
  41. }
  42. return ignore;
  43. }
  44. struct BlockInfo {
  45. u32 start{};
  46. u32 end{};
  47. bool visited{};
  48. BlockBranchInfo branch{};
  49. bool IsInside(const u32 address) const {
  50. return start <= address && address <= end;
  51. }
  52. };
  53. struct CFGRebuildState {
  54. explicit CFGRebuildState(const ProgramCode& program_code, u32 start, ConstBufferLocker& locker)
  55. : program_code{program_code}, start{start}, locker{locker} {}
  56. const ProgramCode& program_code;
  57. ConstBufferLocker& locker;
  58. u32 start{};
  59. std::vector<BlockInfo> block_info{};
  60. std::list<u32> inspect_queries{};
  61. std::list<Query> queries{};
  62. std::unordered_map<u32, u32> registered{};
  63. std::set<u32> labels{};
  64. std::map<u32, u32> ssy_labels{};
  65. std::map<u32, u32> pbk_labels{};
  66. std::unordered_map<u32, BlockStack> stacks{};
  67. ASTManager* manager;
  68. };
  69. enum class BlockCollision : u32 { None, Found, Inside };
  70. std::pair<BlockCollision, u32> TryGetBlock(CFGRebuildState& state, u32 address) {
  71. const auto& blocks = state.block_info;
  72. for (u32 index = 0; index < blocks.size(); index++) {
  73. if (blocks[index].start == address) {
  74. return {BlockCollision::Found, index};
  75. }
  76. if (blocks[index].IsInside(address)) {
  77. return {BlockCollision::Inside, index};
  78. }
  79. }
  80. return {BlockCollision::None, 0xFFFFFFFF};
  81. }
  82. struct ParseInfo {
  83. BlockBranchInfo branch_info{};
  84. u32 end_address{};
  85. };
  86. BlockInfo& CreateBlockInfo(CFGRebuildState& state, u32 start, u32 end) {
  87. auto& it = state.block_info.emplace_back();
  88. it.start = start;
  89. it.end = end;
  90. const u32 index = static_cast<u32>(state.block_info.size() - 1);
  91. state.registered.insert({start, index});
  92. return it;
  93. }
  94. Pred GetPredicate(u32 index, bool negated) {
  95. return static_cast<Pred>(index + (negated ? 8 : 0));
  96. }
  97. /**
  98. * Returns whether the instruction at the specified offset is a 'sched' instruction.
  99. * Sched instructions always appear before a sequence of 3 instructions.
  100. */
  101. constexpr bool IsSchedInstruction(u32 offset, u32 main_offset) {
  102. constexpr u32 SchedPeriod = 4;
  103. u32 absolute_offset = offset - main_offset;
  104. return (absolute_offset % SchedPeriod) == 0;
  105. }
  106. enum class ParseResult : u32 {
  107. ControlCaught,
  108. BlockEnd,
  109. AbnormalFlow,
  110. };
  111. struct BranchIndirectInfo {
  112. u32 buffer{};
  113. u32 offset{};
  114. u32 entries{};
  115. s32 relative_position{};
  116. };
  117. std::optional<BranchIndirectInfo> TrackBranchIndirectInfo(const CFGRebuildState& state,
  118. u32 start_address, u32 current_position) {
  119. const u32 shader_start = state.start;
  120. u32 pos = current_position;
  121. BranchIndirectInfo result{};
  122. u64 track_register = 0;
  123. // Step 0 Get BRX Info
  124. const Instruction instr = {state.program_code[pos]};
  125. const auto opcode = OpCode::Decode(instr);
  126. if (opcode->get().GetId() != OpCode::Id::BRX) {
  127. return std::nullopt;
  128. }
  129. if (instr.brx.constant_buffer != 0) {
  130. return std::nullopt;
  131. }
  132. track_register = instr.gpr8.Value();
  133. result.relative_position = instr.brx.GetBranchExtend();
  134. pos--;
  135. bool found_track = false;
  136. // Step 1 Track LDC
  137. while (pos >= shader_start) {
  138. if (IsSchedInstruction(pos, shader_start)) {
  139. pos--;
  140. continue;
  141. }
  142. const Instruction instr = {state.program_code[pos]};
  143. const auto opcode = OpCode::Decode(instr);
  144. if (opcode->get().GetId() == OpCode::Id::LD_C) {
  145. if (instr.gpr0.Value() == track_register &&
  146. instr.ld_c.type.Value() == Tegra::Shader::UniformType::Single) {
  147. result.buffer = instr.cbuf36.index.Value();
  148. result.offset = static_cast<u32>(instr.cbuf36.GetOffset());
  149. track_register = instr.gpr8.Value();
  150. pos--;
  151. found_track = true;
  152. break;
  153. }
  154. }
  155. pos--;
  156. }
  157. if (!found_track) {
  158. return std::nullopt;
  159. }
  160. found_track = false;
  161. // Step 2 Track SHL
  162. while (pos >= shader_start) {
  163. if (IsSchedInstruction(pos, shader_start)) {
  164. pos--;
  165. continue;
  166. }
  167. const Instruction instr = state.program_code[pos];
  168. const auto opcode = OpCode::Decode(instr);
  169. if (opcode->get().GetId() == OpCode::Id::SHL_IMM) {
  170. if (instr.gpr0.Value() == track_register) {
  171. track_register = instr.gpr8.Value();
  172. pos--;
  173. found_track = true;
  174. break;
  175. }
  176. }
  177. pos--;
  178. }
  179. if (!found_track) {
  180. return std::nullopt;
  181. }
  182. found_track = false;
  183. // Step 3 Track IMNMX
  184. while (pos >= shader_start) {
  185. if (IsSchedInstruction(pos, shader_start)) {
  186. pos--;
  187. continue;
  188. }
  189. const Instruction instr = state.program_code[pos];
  190. const auto opcode = OpCode::Decode(instr);
  191. if (opcode->get().GetId() == OpCode::Id::IMNMX_IMM) {
  192. if (instr.gpr0.Value() == track_register) {
  193. track_register = instr.gpr8.Value();
  194. result.entries = instr.alu.GetSignedImm20_20() + 1;
  195. pos--;
  196. found_track = true;
  197. break;
  198. }
  199. }
  200. pos--;
  201. }
  202. if (!found_track) {
  203. return std::nullopt;
  204. }
  205. return result;
  206. }
  207. std::pair<ParseResult, ParseInfo> ParseCode(CFGRebuildState& state, u32 address) {
  208. u32 offset = static_cast<u32>(address);
  209. const u32 end_address = static_cast<u32>(state.program_code.size());
  210. ParseInfo parse_info{};
  211. SingleBranch single_branch{};
  212. const auto insert_label = [](CFGRebuildState& state, u32 address) {
  213. const auto pair = state.labels.emplace(address);
  214. if (pair.second) {
  215. state.inspect_queries.push_back(address);
  216. }
  217. };
  218. while (true) {
  219. if (offset >= end_address) {
  220. // ASSERT_OR_EXECUTE can't be used, as it ignores the break
  221. ASSERT_MSG(false, "Shader passed the current limit!");
  222. single_branch.address = exit_branch;
  223. single_branch.ignore = false;
  224. break;
  225. }
  226. if (state.registered.count(offset) != 0) {
  227. single_branch.address = offset;
  228. single_branch.ignore = true;
  229. break;
  230. }
  231. if (IsSchedInstruction(offset, state.start)) {
  232. offset++;
  233. continue;
  234. }
  235. const Instruction instr = {state.program_code[offset]};
  236. const auto opcode = OpCode::Decode(instr);
  237. if (!opcode || opcode->get().GetType() != OpCode::Type::Flow) {
  238. offset++;
  239. continue;
  240. }
  241. switch (opcode->get().GetId()) {
  242. case OpCode::Id::EXIT: {
  243. const auto pred_index = static_cast<u32>(instr.pred.pred_index);
  244. single_branch.condition.predicate = GetPredicate(pred_index, instr.negate_pred != 0);
  245. if (single_branch.condition.predicate == Pred::NeverExecute) {
  246. offset++;
  247. continue;
  248. }
  249. const ConditionCode cc = instr.flow_condition_code;
  250. single_branch.condition.cc = cc;
  251. if (cc == ConditionCode::F) {
  252. offset++;
  253. continue;
  254. }
  255. single_branch.address = exit_branch;
  256. single_branch.kill = false;
  257. single_branch.is_sync = false;
  258. single_branch.is_brk = false;
  259. single_branch.ignore = false;
  260. parse_info.end_address = offset;
  261. parse_info.branch_info = MakeBranchInfo<SingleBranch>(
  262. single_branch.condition, single_branch.address, single_branch.kill,
  263. single_branch.is_sync, single_branch.is_brk, single_branch.ignore);
  264. return {ParseResult::ControlCaught, parse_info};
  265. }
  266. case OpCode::Id::BRA: {
  267. if (instr.bra.constant_buffer != 0) {
  268. return {ParseResult::AbnormalFlow, parse_info};
  269. }
  270. const auto pred_index = static_cast<u32>(instr.pred.pred_index);
  271. single_branch.condition.predicate = GetPredicate(pred_index, instr.negate_pred != 0);
  272. if (single_branch.condition.predicate == Pred::NeverExecute) {
  273. offset++;
  274. continue;
  275. }
  276. const ConditionCode cc = instr.flow_condition_code;
  277. single_branch.condition.cc = cc;
  278. if (cc == ConditionCode::F) {
  279. offset++;
  280. continue;
  281. }
  282. const u32 branch_offset = offset + instr.bra.GetBranchTarget();
  283. if (branch_offset == 0) {
  284. single_branch.address = exit_branch;
  285. } else {
  286. single_branch.address = branch_offset;
  287. }
  288. insert_label(state, branch_offset);
  289. single_branch.kill = false;
  290. single_branch.is_sync = false;
  291. single_branch.is_brk = false;
  292. single_branch.ignore = false;
  293. parse_info.end_address = offset;
  294. parse_info.branch_info = MakeBranchInfo<SingleBranch>(
  295. single_branch.condition, single_branch.address, single_branch.kill,
  296. single_branch.is_sync, single_branch.is_brk, single_branch.ignore);
  297. return {ParseResult::ControlCaught, parse_info};
  298. }
  299. case OpCode::Id::SYNC: {
  300. const auto pred_index = static_cast<u32>(instr.pred.pred_index);
  301. single_branch.condition.predicate = GetPredicate(pred_index, instr.negate_pred != 0);
  302. if (single_branch.condition.predicate == Pred::NeverExecute) {
  303. offset++;
  304. continue;
  305. }
  306. const ConditionCode cc = instr.flow_condition_code;
  307. single_branch.condition.cc = cc;
  308. if (cc == ConditionCode::F) {
  309. offset++;
  310. continue;
  311. }
  312. single_branch.address = unassigned_branch;
  313. single_branch.kill = false;
  314. single_branch.is_sync = true;
  315. single_branch.is_brk = false;
  316. single_branch.ignore = false;
  317. parse_info.end_address = offset;
  318. parse_info.branch_info = MakeBranchInfo<SingleBranch>(
  319. single_branch.condition, single_branch.address, single_branch.kill,
  320. single_branch.is_sync, single_branch.is_brk, single_branch.ignore);
  321. return {ParseResult::ControlCaught, parse_info};
  322. }
  323. case OpCode::Id::BRK: {
  324. const auto pred_index = static_cast<u32>(instr.pred.pred_index);
  325. single_branch.condition.predicate = GetPredicate(pred_index, instr.negate_pred != 0);
  326. if (single_branch.condition.predicate == Pred::NeverExecute) {
  327. offset++;
  328. continue;
  329. }
  330. const ConditionCode cc = instr.flow_condition_code;
  331. single_branch.condition.cc = cc;
  332. if (cc == ConditionCode::F) {
  333. offset++;
  334. continue;
  335. }
  336. single_branch.address = unassigned_branch;
  337. single_branch.kill = false;
  338. single_branch.is_sync = false;
  339. single_branch.is_brk = true;
  340. single_branch.ignore = false;
  341. parse_info.end_address = offset;
  342. parse_info.branch_info = MakeBranchInfo<SingleBranch>(
  343. single_branch.condition, single_branch.address, single_branch.kill,
  344. single_branch.is_sync, single_branch.is_brk, single_branch.ignore);
  345. return {ParseResult::ControlCaught, parse_info};
  346. }
  347. case OpCode::Id::KIL: {
  348. const auto pred_index = static_cast<u32>(instr.pred.pred_index);
  349. single_branch.condition.predicate = GetPredicate(pred_index, instr.negate_pred != 0);
  350. if (single_branch.condition.predicate == Pred::NeverExecute) {
  351. offset++;
  352. continue;
  353. }
  354. const ConditionCode cc = instr.flow_condition_code;
  355. single_branch.condition.cc = cc;
  356. if (cc == ConditionCode::F) {
  357. offset++;
  358. continue;
  359. }
  360. single_branch.address = exit_branch;
  361. single_branch.kill = true;
  362. single_branch.is_sync = false;
  363. single_branch.is_brk = false;
  364. single_branch.ignore = false;
  365. parse_info.end_address = offset;
  366. parse_info.branch_info = MakeBranchInfo<SingleBranch>(
  367. single_branch.condition, single_branch.address, single_branch.kill,
  368. single_branch.is_sync, single_branch.is_brk, single_branch.ignore);
  369. return {ParseResult::ControlCaught, parse_info};
  370. }
  371. case OpCode::Id::SSY: {
  372. const u32 target = offset + instr.bra.GetBranchTarget();
  373. insert_label(state, target);
  374. state.ssy_labels.emplace(offset, target);
  375. break;
  376. }
  377. case OpCode::Id::PBK: {
  378. const u32 target = offset + instr.bra.GetBranchTarget();
  379. insert_label(state, target);
  380. state.pbk_labels.emplace(offset, target);
  381. break;
  382. }
  383. case OpCode::Id::BRX: {
  384. auto tmp = TrackBranchIndirectInfo(state, address, offset);
  385. if (tmp) {
  386. auto result = *tmp;
  387. std::vector<CaseBranch> branches{};
  388. s32 pc_target = offset + result.relative_position;
  389. for (u32 i = 0; i < result.entries; i++) {
  390. auto k = state.locker.ObtainKey(result.buffer, result.offset + i * 4);
  391. if (!k) {
  392. return {ParseResult::AbnormalFlow, parse_info};
  393. }
  394. u32 value = *k;
  395. u32 target = static_cast<u32>((value >> 3) + pc_target);
  396. insert_label(state, target);
  397. branches.emplace_back(value, target);
  398. }
  399. parse_info.end_address = offset;
  400. parse_info.branch_info = MakeBranchInfo<MultiBranch>(
  401. static_cast<u32>(instr.gpr8.Value()), std::move(branches));
  402. return {ParseResult::ControlCaught, parse_info};
  403. } else {
  404. LOG_WARNING(HW_GPU, "BRX Track Unsuccesful");
  405. }
  406. return {ParseResult::AbnormalFlow, parse_info};
  407. }
  408. default:
  409. break;
  410. }
  411. offset++;
  412. }
  413. single_branch.kill = false;
  414. single_branch.is_sync = false;
  415. single_branch.is_brk = false;
  416. parse_info.end_address = offset - 1;
  417. parse_info.branch_info = MakeBranchInfo<SingleBranch>(
  418. single_branch.condition, single_branch.address, single_branch.kill, single_branch.is_sync,
  419. single_branch.is_brk, single_branch.ignore);
  420. return {ParseResult::BlockEnd, parse_info};
  421. }
  422. bool TryInspectAddress(CFGRebuildState& state) {
  423. if (state.inspect_queries.empty()) {
  424. return false;
  425. }
  426. const u32 address = state.inspect_queries.front();
  427. state.inspect_queries.pop_front();
  428. const auto [result, block_index] = TryGetBlock(state, address);
  429. switch (result) {
  430. case BlockCollision::Found: {
  431. return true;
  432. }
  433. case BlockCollision::Inside: {
  434. // This case is the tricky one:
  435. // We need to Split the block in 2 sepparate blocks
  436. const u32 end = state.block_info[block_index].end;
  437. BlockInfo& new_block = CreateBlockInfo(state, address, end);
  438. BlockInfo& current_block = state.block_info[block_index];
  439. current_block.end = address - 1;
  440. new_block.branch = current_block.branch;
  441. BlockBranchInfo forward_branch = MakeBranchInfo<SingleBranch>();
  442. const auto branch = std::get_if<SingleBranch>(forward_branch.get());
  443. branch->address = address;
  444. branch->ignore = true;
  445. current_block.branch = forward_branch;
  446. return true;
  447. }
  448. default:
  449. break;
  450. }
  451. const auto [parse_result, parse_info] = ParseCode(state, address);
  452. if (parse_result == ParseResult::AbnormalFlow) {
  453. // if it's AbnormalFlow, we end it as false, ending the CFG reconstruction
  454. return false;
  455. }
  456. BlockInfo& block_info = CreateBlockInfo(state, address, parse_info.end_address);
  457. block_info.branch = parse_info.branch_info;
  458. if (std::holds_alternative<SingleBranch>(*block_info.branch)) {
  459. const auto branch = std::get_if<SingleBranch>(block_info.branch.get());
  460. if (branch->condition.IsUnconditional()) {
  461. return true;
  462. }
  463. const u32 fallthrough_address = parse_info.end_address + 1;
  464. state.inspect_queries.push_front(fallthrough_address);
  465. return true;
  466. }
  467. return true;
  468. }
  469. bool TryQuery(CFGRebuildState& state) {
  470. const auto gather_labels = [](std::stack<u32>& cc, std::map<u32, u32>& labels,
  471. BlockInfo& block) {
  472. auto gather_start = labels.lower_bound(block.start);
  473. const auto gather_end = labels.upper_bound(block.end);
  474. while (gather_start != gather_end) {
  475. cc.push(gather_start->second);
  476. ++gather_start;
  477. }
  478. };
  479. if (state.queries.empty()) {
  480. return false;
  481. }
  482. Query& q = state.queries.front();
  483. const u32 block_index = state.registered[q.address];
  484. BlockInfo& block = state.block_info[block_index];
  485. // If the block is visited, check if the stacks match, else gather the ssy/pbk
  486. // labels into the current stack and look if the branch at the end of the block
  487. // consumes a label. Schedule new queries accordingly
  488. if (block.visited) {
  489. BlockStack& stack = state.stacks[q.address];
  490. const bool all_okay = (stack.ssy_stack.empty() || q.ssy_stack == stack.ssy_stack) &&
  491. (stack.pbk_stack.empty() || q.pbk_stack == stack.pbk_stack);
  492. state.queries.pop_front();
  493. return all_okay;
  494. }
  495. block.visited = true;
  496. state.stacks.insert_or_assign(q.address, BlockStack{q});
  497. Query q2(q);
  498. state.queries.pop_front();
  499. gather_labels(q2.ssy_stack, state.ssy_labels, block);
  500. gather_labels(q2.pbk_stack, state.pbk_labels, block);
  501. if (std::holds_alternative<SingleBranch>(*block.branch)) {
  502. const auto branch = std::get_if<SingleBranch>(block.branch.get());
  503. if (!branch->condition.IsUnconditional()) {
  504. q2.address = block.end + 1;
  505. state.queries.push_back(q2);
  506. }
  507. Query conditional_query{q2};
  508. if (branch->is_sync) {
  509. if (branch->address == unassigned_branch) {
  510. branch->address = conditional_query.ssy_stack.top();
  511. }
  512. conditional_query.ssy_stack.pop();
  513. }
  514. if (branch->is_brk) {
  515. if (branch->address == unassigned_branch) {
  516. branch->address = conditional_query.pbk_stack.top();
  517. }
  518. conditional_query.pbk_stack.pop();
  519. }
  520. conditional_query.address = branch->address;
  521. state.queries.push_back(std::move(conditional_query));
  522. return true;
  523. }
  524. const auto multi_branch = std::get_if<MultiBranch>(block.branch.get());
  525. for (const auto& branch_case : multi_branch->branches) {
  526. Query conditional_query{q2};
  527. conditional_query.address = branch_case.address;
  528. state.queries.push_back(std::move(conditional_query));
  529. }
  530. return true;
  531. }
  532. } // Anonymous namespace
  533. void InsertBranch(ASTManager& mm, const BlockBranchInfo& branch_info) {
  534. const auto get_expr = ([&](const Condition& cond) -> Expr {
  535. Expr result{};
  536. if (cond.cc != ConditionCode::T) {
  537. result = MakeExpr<ExprCondCode>(cond.cc);
  538. }
  539. if (cond.predicate != Pred::UnusedIndex) {
  540. u32 pred = static_cast<u32>(cond.predicate);
  541. bool negate = false;
  542. if (pred > 7) {
  543. negate = true;
  544. pred -= 8;
  545. }
  546. Expr extra = MakeExpr<ExprPredicate>(pred);
  547. if (negate) {
  548. extra = MakeExpr<ExprNot>(extra);
  549. }
  550. if (result) {
  551. return MakeExpr<ExprAnd>(extra, result);
  552. }
  553. return extra;
  554. }
  555. if (result) {
  556. return result;
  557. }
  558. return MakeExpr<ExprBoolean>(true);
  559. });
  560. if (std::holds_alternative<SingleBranch>(*branch_info)) {
  561. const auto branch = std::get_if<SingleBranch>(branch_info.get());
  562. if (branch->address < 0) {
  563. if (branch->kill) {
  564. mm.InsertReturn(get_expr(branch->condition), true);
  565. return;
  566. }
  567. mm.InsertReturn(get_expr(branch->condition), false);
  568. return;
  569. }
  570. mm.InsertGoto(get_expr(branch->condition), branch->address);
  571. return;
  572. }
  573. const auto multi_branch = std::get_if<MultiBranch>(branch_info.get());
  574. for (const auto& branch_case : multi_branch->branches) {
  575. mm.InsertGoto(MakeExpr<ExprGprEqual>(multi_branch->gpr, branch_case.cmp_value),
  576. branch_case.address);
  577. }
  578. }
  579. void DecompileShader(CFGRebuildState& state) {
  580. state.manager->Init();
  581. for (auto label : state.labels) {
  582. state.manager->DeclareLabel(label);
  583. }
  584. for (auto& block : state.block_info) {
  585. if (state.labels.count(block.start) != 0) {
  586. state.manager->InsertLabel(block.start);
  587. }
  588. const bool ignore = BlockBranchIsIgnored(block.branch);
  589. u32 end = ignore ? block.end + 1 : block.end;
  590. state.manager->InsertBlock(block.start, end);
  591. if (!ignore) {
  592. InsertBranch(*state.manager, block.branch);
  593. }
  594. }
  595. state.manager->Decompile();
  596. }
  597. std::unique_ptr<ShaderCharacteristics> ScanFlow(const ProgramCode& program_code, u32 start_address,
  598. const CompilerSettings& settings,
  599. ConstBufferLocker& locker) {
  600. auto result_out = std::make_unique<ShaderCharacteristics>();
  601. if (settings.depth == CompileDepth::BruteForce) {
  602. result_out->settings.depth = CompileDepth::BruteForce;
  603. return result_out;
  604. }
  605. CFGRebuildState state{program_code, start_address, locker};
  606. // Inspect Code and generate blocks
  607. state.labels.clear();
  608. state.labels.emplace(start_address);
  609. state.inspect_queries.push_back(state.start);
  610. while (!state.inspect_queries.empty()) {
  611. if (!TryInspectAddress(state)) {
  612. result_out->settings.depth = CompileDepth::BruteForce;
  613. return result_out;
  614. }
  615. }
  616. bool use_flow_stack = true;
  617. bool decompiled = false;
  618. if (settings.depth != CompileDepth::FlowStack) {
  619. // Decompile Stacks
  620. state.queries.push_back(Query{state.start, {}, {}});
  621. decompiled = true;
  622. while (!state.queries.empty()) {
  623. if (!TryQuery(state)) {
  624. decompiled = false;
  625. break;
  626. }
  627. }
  628. }
  629. use_flow_stack = !decompiled;
  630. // Sort and organize results
  631. std::sort(state.block_info.begin(), state.block_info.end(),
  632. [](const BlockInfo& a, const BlockInfo& b) -> bool { return a.start < b.start; });
  633. if (decompiled && settings.depth != CompileDepth::NoFlowStack) {
  634. ASTManager manager{settings.depth != CompileDepth::DecompileBackwards,
  635. settings.disable_else_derivation};
  636. state.manager = &manager;
  637. DecompileShader(state);
  638. decompiled = state.manager->IsFullyDecompiled();
  639. if (!decompiled) {
  640. if (settings.depth == CompileDepth::FullDecompile) {
  641. LOG_CRITICAL(HW_GPU, "Failed to remove all the gotos!:");
  642. } else {
  643. LOG_CRITICAL(HW_GPU, "Failed to remove all backward gotos!:");
  644. }
  645. state.manager->ShowCurrentState("Of Shader");
  646. state.manager->Clear();
  647. } else {
  648. auto characteristics = std::make_unique<ShaderCharacteristics>();
  649. characteristics->start = start_address;
  650. characteristics->settings.depth = settings.depth;
  651. characteristics->manager = std::move(manager);
  652. characteristics->end = state.block_info.back().end + 1;
  653. return characteristics;
  654. }
  655. }
  656. result_out->start = start_address;
  657. result_out->settings.depth =
  658. use_flow_stack ? CompileDepth::FlowStack : CompileDepth::NoFlowStack;
  659. result_out->blocks.clear();
  660. for (auto& block : state.block_info) {
  661. ShaderBlock new_block{};
  662. new_block.start = block.start;
  663. new_block.end = block.end;
  664. new_block.ignore_branch = BlockBranchIsIgnored(block.branch);
  665. if (!new_block.ignore_branch) {
  666. new_block.branch = block.branch;
  667. }
  668. result_out->end = std::max(result_out->end, block.end);
  669. result_out->blocks.push_back(new_block);
  670. }
  671. if (!use_flow_stack) {
  672. result_out->labels = std::move(state.labels);
  673. return result_out;
  674. }
  675. auto back = result_out->blocks.begin();
  676. auto next = std::next(back);
  677. while (next != result_out->blocks.end()) {
  678. if (state.labels.count(next->start) == 0 && next->start == back->end + 1) {
  679. back->end = next->end;
  680. next = result_out->blocks.erase(next);
  681. continue;
  682. }
  683. back = next;
  684. ++next;
  685. }
  686. return result_out;
  687. }
  688. } // namespace VideoCommon::Shader