control_flow.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758
  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/registry.h"
  15. #include "video_core/shader/shader_ir.h"
  16. namespace VideoCommon::Shader {
  17. namespace {
  18. using Tegra::Shader::Instruction;
  19. using Tegra::Shader::OpCode;
  20. constexpr s32 unassigned_branch = -2;
  21. struct Query {
  22. u32 address{};
  23. std::stack<u32> ssy_stack{};
  24. std::stack<u32> pbk_stack{};
  25. };
  26. struct BlockStack {
  27. BlockStack() = default;
  28. explicit BlockStack(const Query& q) : ssy_stack{q.ssy_stack}, pbk_stack{q.pbk_stack} {}
  29. std::stack<u32> ssy_stack{};
  30. std::stack<u32> pbk_stack{};
  31. };
  32. template <typename T, typename... Args>
  33. BlockBranchInfo MakeBranchInfo(Args&&... args) {
  34. static_assert(std::is_convertible_v<T, BranchData>);
  35. return std::make_shared<BranchData>(T(std::forward<Args>(args)...));
  36. }
  37. bool BlockBranchIsIgnored(BlockBranchInfo first) {
  38. bool ignore = false;
  39. if (std::holds_alternative<SingleBranch>(*first)) {
  40. const auto branch = std::get_if<SingleBranch>(first.get());
  41. ignore = branch->ignore;
  42. }
  43. return ignore;
  44. }
  45. struct BlockInfo {
  46. u32 start{};
  47. u32 end{};
  48. bool visited{};
  49. BlockBranchInfo branch{};
  50. bool IsInside(const u32 address) const {
  51. return start <= address && address <= end;
  52. }
  53. };
  54. struct CFGRebuildState {
  55. explicit CFGRebuildState(const ProgramCode& program_code, u32 start, Registry& registry)
  56. : program_code{program_code}, registry{registry}, start{start} {}
  57. const ProgramCode& program_code;
  58. Registry& registry;
  59. u32 start{};
  60. std::vector<BlockInfo> block_info;
  61. std::list<u32> inspect_queries;
  62. std::list<Query> queries;
  63. std::unordered_map<u32, u32> registered;
  64. std::set<u32> labels;
  65. std::map<u32, u32> ssy_labels;
  66. std::map<u32, u32> pbk_labels;
  67. std::unordered_map<u32, BlockStack> stacks;
  68. ASTManager* manager{};
  69. };
  70. enum class BlockCollision : u32 { None, Found, Inside };
  71. std::pair<BlockCollision, u32> TryGetBlock(CFGRebuildState& state, u32 address) {
  72. const auto& blocks = state.block_info;
  73. for (u32 index = 0; index < blocks.size(); index++) {
  74. if (blocks[index].start == address) {
  75. return {BlockCollision::Found, index};
  76. }
  77. if (blocks[index].IsInside(address)) {
  78. return {BlockCollision::Inside, index};
  79. }
  80. }
  81. return {BlockCollision::None, 0xFFFFFFFF};
  82. }
  83. struct ParseInfo {
  84. BlockBranchInfo branch_info{};
  85. u32 end_address{};
  86. };
  87. BlockInfo& CreateBlockInfo(CFGRebuildState& state, u32 start, u32 end) {
  88. auto& it = state.block_info.emplace_back();
  89. it.start = start;
  90. it.end = end;
  91. const u32 index = static_cast<u32>(state.block_info.size() - 1);
  92. state.registered.insert({start, index});
  93. return it;
  94. }
  95. Pred GetPredicate(u32 index, bool negated) {
  96. return static_cast<Pred>(static_cast<u64>(index) + (negated ? 8ULL : 0ULL));
  97. }
  98. /**
  99. * Returns whether the instruction at the specified offset is a 'sched' instruction.
  100. * Sched instructions always appear before a sequence of 3 instructions.
  101. */
  102. constexpr bool IsSchedInstruction(u32 offset, u32 main_offset) {
  103. constexpr u32 SchedPeriod = 4;
  104. u32 absolute_offset = offset - main_offset;
  105. return (absolute_offset % SchedPeriod) == 0;
  106. }
  107. enum class ParseResult : u32 {
  108. ControlCaught,
  109. BlockEnd,
  110. AbnormalFlow,
  111. };
  112. struct BranchIndirectInfo {
  113. u32 buffer{};
  114. u32 offset{};
  115. u32 entries{};
  116. s32 relative_position{};
  117. };
  118. struct BufferInfo {
  119. u32 index;
  120. u32 offset;
  121. };
  122. std::optional<std::pair<s32, u64>> GetBRXInfo(const CFGRebuildState& state, u32& pos) {
  123. const Instruction instr = state.program_code[pos];
  124. const auto opcode = OpCode::Decode(instr);
  125. if (opcode->get().GetId() != OpCode::Id::BRX) {
  126. return std::nullopt;
  127. }
  128. if (instr.brx.constant_buffer != 0) {
  129. return std::nullopt;
  130. }
  131. --pos;
  132. return std::make_pair(instr.brx.GetBranchExtend(), instr.gpr8.Value());
  133. }
  134. template <typename Result, typename TestCallable, typename PackCallable>
  135. // requires std::predicate<TestCallable, Instruction, const OpCode::Matcher&>
  136. // requires std::invocable<PackCallable, Instruction, const OpCode::Matcher&>
  137. std::optional<Result> TrackInstruction(const CFGRebuildState& state, u32& pos, TestCallable test,
  138. PackCallable pack) {
  139. for (; pos >= state.start; --pos) {
  140. if (IsSchedInstruction(pos, state.start)) {
  141. continue;
  142. }
  143. const Instruction instr = state.program_code[pos];
  144. const auto opcode = OpCode::Decode(instr);
  145. if (!opcode) {
  146. continue;
  147. }
  148. if (test(instr, opcode->get())) {
  149. --pos;
  150. return std::make_optional(pack(instr, opcode->get()));
  151. }
  152. }
  153. return std::nullopt;
  154. }
  155. std::optional<std::pair<BufferInfo, u64>> TrackLDC(const CFGRebuildState& state, u32& pos,
  156. u64 brx_tracked_register) {
  157. return TrackInstruction<std::pair<BufferInfo, u64>>(
  158. state, pos,
  159. [brx_tracked_register](auto instr, const auto& opcode) {
  160. return opcode.GetId() == OpCode::Id::LD_C &&
  161. instr.gpr0.Value() == brx_tracked_register &&
  162. instr.ld_c.type.Value() == Tegra::Shader::UniformType::Single;
  163. },
  164. [](auto instr, const auto& opcode) {
  165. const BufferInfo info = {static_cast<u32>(instr.cbuf36.index.Value()),
  166. static_cast<u32>(instr.cbuf36.GetOffset())};
  167. return std::make_pair(info, instr.gpr8.Value());
  168. });
  169. }
  170. std::optional<u64> TrackSHLRegister(const CFGRebuildState& state, u32& pos,
  171. u64 ldc_tracked_register) {
  172. return TrackInstruction<u64>(state, pos,
  173. [ldc_tracked_register](auto instr, const auto& opcode) {
  174. return opcode.GetId() == OpCode::Id::SHL_IMM &&
  175. instr.gpr0.Value() == ldc_tracked_register;
  176. },
  177. [](auto instr, const auto&) { return instr.gpr8.Value(); });
  178. }
  179. std::optional<u32> TrackIMNMXValue(const CFGRebuildState& state, u32& pos,
  180. u64 shl_tracked_register) {
  181. return TrackInstruction<u32>(state, pos,
  182. [shl_tracked_register](auto instr, const auto& opcode) {
  183. return opcode.GetId() == OpCode::Id::IMNMX_IMM &&
  184. instr.gpr0.Value() == shl_tracked_register;
  185. },
  186. [](auto instr, const auto&) {
  187. return static_cast<u32>(instr.alu.GetSignedImm20_20() + 1);
  188. });
  189. }
  190. std::optional<BranchIndirectInfo> TrackBranchIndirectInfo(const CFGRebuildState& state, u32 pos) {
  191. const auto brx_info = GetBRXInfo(state, pos);
  192. if (!brx_info) {
  193. return std::nullopt;
  194. }
  195. const auto [relative_position, brx_tracked_register] = *brx_info;
  196. const auto ldc_info = TrackLDC(state, pos, brx_tracked_register);
  197. if (!ldc_info) {
  198. return std::nullopt;
  199. }
  200. const auto [buffer_info, ldc_tracked_register] = *ldc_info;
  201. const auto shl_tracked_register = TrackSHLRegister(state, pos, ldc_tracked_register);
  202. if (!shl_tracked_register) {
  203. return std::nullopt;
  204. }
  205. const auto entries = TrackIMNMXValue(state, pos, *shl_tracked_register);
  206. if (!entries) {
  207. return std::nullopt;
  208. }
  209. return BranchIndirectInfo{buffer_info.index, buffer_info.offset, *entries, relative_position};
  210. }
  211. std::pair<ParseResult, ParseInfo> ParseCode(CFGRebuildState& state, u32 address) {
  212. u32 offset = static_cast<u32>(address);
  213. const u32 end_address = static_cast<u32>(state.program_code.size());
  214. ParseInfo parse_info{};
  215. SingleBranch single_branch{};
  216. const auto insert_label = [](CFGRebuildState& state, u32 address) {
  217. const auto pair = state.labels.emplace(address);
  218. if (pair.second) {
  219. state.inspect_queries.push_back(address);
  220. }
  221. };
  222. while (true) {
  223. if (offset >= end_address) {
  224. // ASSERT_OR_EXECUTE can't be used, as it ignores the break
  225. ASSERT_MSG(false, "Shader passed the current limit!");
  226. single_branch.address = exit_branch;
  227. single_branch.ignore = false;
  228. break;
  229. }
  230. if (state.registered.count(offset) != 0) {
  231. single_branch.address = offset;
  232. single_branch.ignore = true;
  233. break;
  234. }
  235. if (IsSchedInstruction(offset, state.start)) {
  236. offset++;
  237. continue;
  238. }
  239. const Instruction instr = {state.program_code[offset]};
  240. const auto opcode = OpCode::Decode(instr);
  241. if (!opcode || opcode->get().GetType() != OpCode::Type::Flow) {
  242. offset++;
  243. continue;
  244. }
  245. switch (opcode->get().GetId()) {
  246. case OpCode::Id::EXIT: {
  247. const auto pred_index = static_cast<u32>(instr.pred.pred_index);
  248. single_branch.condition.predicate = GetPredicate(pred_index, instr.negate_pred != 0);
  249. if (single_branch.condition.predicate == Pred::NeverExecute) {
  250. offset++;
  251. continue;
  252. }
  253. const ConditionCode cc = instr.flow_condition_code;
  254. single_branch.condition.cc = cc;
  255. if (cc == ConditionCode::F) {
  256. offset++;
  257. continue;
  258. }
  259. single_branch.address = exit_branch;
  260. single_branch.kill = false;
  261. single_branch.is_sync = false;
  262. single_branch.is_brk = false;
  263. single_branch.ignore = false;
  264. parse_info.end_address = offset;
  265. parse_info.branch_info = MakeBranchInfo<SingleBranch>(
  266. single_branch.condition, single_branch.address, single_branch.kill,
  267. single_branch.is_sync, single_branch.is_brk, single_branch.ignore);
  268. return {ParseResult::ControlCaught, parse_info};
  269. }
  270. case OpCode::Id::BRA: {
  271. if (instr.bra.constant_buffer != 0) {
  272. return {ParseResult::AbnormalFlow, parse_info};
  273. }
  274. const auto pred_index = static_cast<u32>(instr.pred.pred_index);
  275. single_branch.condition.predicate = GetPredicate(pred_index, instr.negate_pred != 0);
  276. if (single_branch.condition.predicate == Pred::NeverExecute) {
  277. offset++;
  278. continue;
  279. }
  280. const ConditionCode cc = instr.flow_condition_code;
  281. single_branch.condition.cc = cc;
  282. if (cc == ConditionCode::F) {
  283. offset++;
  284. continue;
  285. }
  286. const u32 branch_offset = offset + instr.bra.GetBranchTarget();
  287. if (branch_offset == 0) {
  288. single_branch.address = exit_branch;
  289. } else {
  290. single_branch.address = branch_offset;
  291. }
  292. insert_label(state, branch_offset);
  293. single_branch.kill = false;
  294. single_branch.is_sync = false;
  295. single_branch.is_brk = false;
  296. single_branch.ignore = false;
  297. parse_info.end_address = offset;
  298. parse_info.branch_info = MakeBranchInfo<SingleBranch>(
  299. single_branch.condition, single_branch.address, single_branch.kill,
  300. single_branch.is_sync, single_branch.is_brk, single_branch.ignore);
  301. return {ParseResult::ControlCaught, parse_info};
  302. }
  303. case OpCode::Id::SYNC: {
  304. const auto pred_index = static_cast<u32>(instr.pred.pred_index);
  305. single_branch.condition.predicate = GetPredicate(pred_index, instr.negate_pred != 0);
  306. if (single_branch.condition.predicate == Pred::NeverExecute) {
  307. offset++;
  308. continue;
  309. }
  310. const ConditionCode cc = instr.flow_condition_code;
  311. single_branch.condition.cc = cc;
  312. if (cc == ConditionCode::F) {
  313. offset++;
  314. continue;
  315. }
  316. single_branch.address = unassigned_branch;
  317. single_branch.kill = false;
  318. single_branch.is_sync = true;
  319. single_branch.is_brk = false;
  320. single_branch.ignore = false;
  321. parse_info.end_address = offset;
  322. parse_info.branch_info = MakeBranchInfo<SingleBranch>(
  323. single_branch.condition, single_branch.address, single_branch.kill,
  324. single_branch.is_sync, single_branch.is_brk, single_branch.ignore);
  325. return {ParseResult::ControlCaught, parse_info};
  326. }
  327. case OpCode::Id::BRK: {
  328. const auto pred_index = static_cast<u32>(instr.pred.pred_index);
  329. single_branch.condition.predicate = GetPredicate(pred_index, instr.negate_pred != 0);
  330. if (single_branch.condition.predicate == Pred::NeverExecute) {
  331. offset++;
  332. continue;
  333. }
  334. const ConditionCode cc = instr.flow_condition_code;
  335. single_branch.condition.cc = cc;
  336. if (cc == ConditionCode::F) {
  337. offset++;
  338. continue;
  339. }
  340. single_branch.address = unassigned_branch;
  341. single_branch.kill = false;
  342. single_branch.is_sync = false;
  343. single_branch.is_brk = true;
  344. single_branch.ignore = false;
  345. parse_info.end_address = offset;
  346. parse_info.branch_info = MakeBranchInfo<SingleBranch>(
  347. single_branch.condition, single_branch.address, single_branch.kill,
  348. single_branch.is_sync, single_branch.is_brk, single_branch.ignore);
  349. return {ParseResult::ControlCaught, parse_info};
  350. }
  351. case OpCode::Id::KIL: {
  352. const auto pred_index = static_cast<u32>(instr.pred.pred_index);
  353. single_branch.condition.predicate = GetPredicate(pred_index, instr.negate_pred != 0);
  354. if (single_branch.condition.predicate == Pred::NeverExecute) {
  355. offset++;
  356. continue;
  357. }
  358. const ConditionCode cc = instr.flow_condition_code;
  359. single_branch.condition.cc = cc;
  360. if (cc == ConditionCode::F) {
  361. offset++;
  362. continue;
  363. }
  364. single_branch.address = exit_branch;
  365. single_branch.kill = true;
  366. single_branch.is_sync = false;
  367. single_branch.is_brk = false;
  368. single_branch.ignore = false;
  369. parse_info.end_address = offset;
  370. parse_info.branch_info = MakeBranchInfo<SingleBranch>(
  371. single_branch.condition, single_branch.address, single_branch.kill,
  372. single_branch.is_sync, single_branch.is_brk, single_branch.ignore);
  373. return {ParseResult::ControlCaught, parse_info};
  374. }
  375. case OpCode::Id::SSY: {
  376. const u32 target = offset + instr.bra.GetBranchTarget();
  377. insert_label(state, target);
  378. state.ssy_labels.emplace(offset, target);
  379. break;
  380. }
  381. case OpCode::Id::PBK: {
  382. const u32 target = offset + instr.bra.GetBranchTarget();
  383. insert_label(state, target);
  384. state.pbk_labels.emplace(offset, target);
  385. break;
  386. }
  387. case OpCode::Id::BRX: {
  388. const auto tmp = TrackBranchIndirectInfo(state, offset);
  389. if (!tmp) {
  390. LOG_WARNING(HW_GPU, "BRX Track Unsuccesful");
  391. return {ParseResult::AbnormalFlow, parse_info};
  392. }
  393. const auto result = *tmp;
  394. const s32 pc_target = offset + result.relative_position;
  395. std::vector<CaseBranch> branches;
  396. for (u32 i = 0; i < result.entries; i++) {
  397. auto key = state.registry.ObtainKey(result.buffer, result.offset + i * 4);
  398. if (!key) {
  399. return {ParseResult::AbnormalFlow, parse_info};
  400. }
  401. u32 value = *key;
  402. u32 target = static_cast<u32>((value >> 3) + pc_target);
  403. insert_label(state, target);
  404. branches.emplace_back(value, target);
  405. }
  406. parse_info.end_address = offset;
  407. parse_info.branch_info = MakeBranchInfo<MultiBranch>(
  408. static_cast<u32>(instr.gpr8.Value()), std::move(branches));
  409. return {ParseResult::ControlCaught, 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. const 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. const 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. const 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. const auto multi_branch = std::get_if<MultiBranch>(block.branch.get());
  528. for (const 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. const 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. const auto multi_branch = std::get_if<MultiBranch>(branch_info.get());
  577. for (const 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. Registry& registry) {
  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, registry};
  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