control_flow.cpp 26 KB

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