control_flow.cpp 27 KB

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