control_flow.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578
  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. struct BlockBranchInfo {
  32. Condition condition{};
  33. s32 address{exit_branch};
  34. bool kill{};
  35. bool is_sync{};
  36. bool is_brk{};
  37. bool ignore{};
  38. };
  39. struct BlockInfo {
  40. u32 start{};
  41. u32 end{};
  42. bool visited{};
  43. BlockBranchInfo branch{};
  44. bool IsInside(const u32 address) const {
  45. return start <= address && address <= end;
  46. }
  47. };
  48. struct CFGRebuildState {
  49. explicit CFGRebuildState(const ProgramCode& program_code, const std::size_t program_size,
  50. const u32 start)
  51. : start{start}, program_code{program_code}, program_size{program_size} {}
  52. u32 start{};
  53. std::vector<BlockInfo> block_info{};
  54. std::list<u32> inspect_queries{};
  55. std::list<Query> queries{};
  56. std::unordered_map<u32, u32> registered{};
  57. std::set<u32> labels{};
  58. std::map<u32, u32> ssy_labels{};
  59. std::map<u32, u32> pbk_labels{};
  60. std::unordered_map<u32, BlockStack> stacks{};
  61. const ProgramCode& program_code;
  62. const std::size_t program_size;
  63. ASTManager* manager;
  64. };
  65. enum class BlockCollision : u32 { None, Found, Inside };
  66. std::pair<BlockCollision, u32> TryGetBlock(CFGRebuildState& state, u32 address) {
  67. const auto& blocks = state.block_info;
  68. for (u32 index = 0; index < blocks.size(); index++) {
  69. if (blocks[index].start == address) {
  70. return {BlockCollision::Found, index};
  71. }
  72. if (blocks[index].IsInside(address)) {
  73. return {BlockCollision::Inside, index};
  74. }
  75. }
  76. return {BlockCollision::None, 0xFFFFFFFF};
  77. }
  78. struct ParseInfo {
  79. BlockBranchInfo branch_info{};
  80. u32 end_address{};
  81. };
  82. BlockInfo& CreateBlockInfo(CFGRebuildState& state, u32 start, u32 end) {
  83. auto& it = state.block_info.emplace_back();
  84. it.start = start;
  85. it.end = end;
  86. const u32 index = static_cast<u32>(state.block_info.size() - 1);
  87. state.registered.insert({start, index});
  88. return it;
  89. }
  90. Pred GetPredicate(u32 index, bool negated) {
  91. return static_cast<Pred>(index + (negated ? 8 : 0));
  92. }
  93. /**
  94. * Returns whether the instruction at the specified offset is a 'sched' instruction.
  95. * Sched instructions always appear before a sequence of 3 instructions.
  96. */
  97. constexpr bool IsSchedInstruction(u32 offset, u32 main_offset) {
  98. constexpr u32 SchedPeriod = 4;
  99. u32 absolute_offset = offset - main_offset;
  100. return (absolute_offset % SchedPeriod) == 0;
  101. }
  102. enum class ParseResult : u32 {
  103. ControlCaught,
  104. BlockEnd,
  105. AbnormalFlow,
  106. };
  107. std::pair<ParseResult, ParseInfo> ParseCode(CFGRebuildState& state, u32 address) {
  108. u32 offset = static_cast<u32>(address);
  109. const u32 end_address = static_cast<u32>(state.program_size / sizeof(Instruction));
  110. ParseInfo parse_info{};
  111. const auto insert_label = [](CFGRebuildState& state, u32 address) {
  112. const auto pair = state.labels.emplace(address);
  113. if (pair.second) {
  114. state.inspect_queries.push_back(address);
  115. }
  116. };
  117. while (true) {
  118. if (offset >= end_address) {
  119. // ASSERT_OR_EXECUTE can't be used, as it ignores the break
  120. ASSERT_MSG(false, "Shader passed the current limit!");
  121. parse_info.branch_info.address = exit_branch;
  122. parse_info.branch_info.ignore = false;
  123. break;
  124. }
  125. if (state.registered.count(offset) != 0) {
  126. parse_info.branch_info.address = offset;
  127. parse_info.branch_info.ignore = true;
  128. break;
  129. }
  130. if (IsSchedInstruction(offset, state.start)) {
  131. offset++;
  132. continue;
  133. }
  134. const Instruction instr = {state.program_code[offset]};
  135. const auto opcode = OpCode::Decode(instr);
  136. if (!opcode || opcode->get().GetType() != OpCode::Type::Flow) {
  137. offset++;
  138. continue;
  139. }
  140. switch (opcode->get().GetId()) {
  141. case OpCode::Id::EXIT: {
  142. const auto pred_index = static_cast<u32>(instr.pred.pred_index);
  143. parse_info.branch_info.condition.predicate =
  144. GetPredicate(pred_index, instr.negate_pred != 0);
  145. if (parse_info.branch_info.condition.predicate == Pred::NeverExecute) {
  146. offset++;
  147. continue;
  148. }
  149. const ConditionCode cc = instr.flow_condition_code;
  150. parse_info.branch_info.condition.cc = cc;
  151. if (cc == ConditionCode::F) {
  152. offset++;
  153. continue;
  154. }
  155. parse_info.branch_info.address = exit_branch;
  156. parse_info.branch_info.kill = false;
  157. parse_info.branch_info.is_sync = false;
  158. parse_info.branch_info.is_brk = false;
  159. parse_info.branch_info.ignore = false;
  160. parse_info.end_address = offset;
  161. return {ParseResult::ControlCaught, parse_info};
  162. }
  163. case OpCode::Id::BRA: {
  164. if (instr.bra.constant_buffer != 0) {
  165. return {ParseResult::AbnormalFlow, parse_info};
  166. }
  167. const auto pred_index = static_cast<u32>(instr.pred.pred_index);
  168. parse_info.branch_info.condition.predicate =
  169. GetPredicate(pred_index, instr.negate_pred != 0);
  170. if (parse_info.branch_info.condition.predicate == Pred::NeverExecute) {
  171. offset++;
  172. continue;
  173. }
  174. const ConditionCode cc = instr.flow_condition_code;
  175. parse_info.branch_info.condition.cc = cc;
  176. if (cc == ConditionCode::F) {
  177. offset++;
  178. continue;
  179. }
  180. const u32 branch_offset = offset + instr.bra.GetBranchTarget();
  181. if (branch_offset == 0) {
  182. parse_info.branch_info.address = exit_branch;
  183. } else {
  184. parse_info.branch_info.address = branch_offset;
  185. }
  186. insert_label(state, branch_offset);
  187. parse_info.branch_info.kill = false;
  188. parse_info.branch_info.is_sync = false;
  189. parse_info.branch_info.is_brk = false;
  190. parse_info.branch_info.ignore = false;
  191. parse_info.end_address = offset;
  192. return {ParseResult::ControlCaught, parse_info};
  193. }
  194. case OpCode::Id::SYNC: {
  195. const auto pred_index = static_cast<u32>(instr.pred.pred_index);
  196. parse_info.branch_info.condition.predicate =
  197. GetPredicate(pred_index, instr.negate_pred != 0);
  198. if (parse_info.branch_info.condition.predicate == Pred::NeverExecute) {
  199. offset++;
  200. continue;
  201. }
  202. const ConditionCode cc = instr.flow_condition_code;
  203. parse_info.branch_info.condition.cc = cc;
  204. if (cc == ConditionCode::F) {
  205. offset++;
  206. continue;
  207. }
  208. parse_info.branch_info.address = unassigned_branch;
  209. parse_info.branch_info.kill = false;
  210. parse_info.branch_info.is_sync = true;
  211. parse_info.branch_info.is_brk = false;
  212. parse_info.branch_info.ignore = false;
  213. parse_info.end_address = offset;
  214. return {ParseResult::ControlCaught, parse_info};
  215. }
  216. case OpCode::Id::BRK: {
  217. const auto pred_index = static_cast<u32>(instr.pred.pred_index);
  218. parse_info.branch_info.condition.predicate =
  219. GetPredicate(pred_index, instr.negate_pred != 0);
  220. if (parse_info.branch_info.condition.predicate == Pred::NeverExecute) {
  221. offset++;
  222. continue;
  223. }
  224. const ConditionCode cc = instr.flow_condition_code;
  225. parse_info.branch_info.condition.cc = cc;
  226. if (cc == ConditionCode::F) {
  227. offset++;
  228. continue;
  229. }
  230. parse_info.branch_info.address = unassigned_branch;
  231. parse_info.branch_info.kill = false;
  232. parse_info.branch_info.is_sync = false;
  233. parse_info.branch_info.is_brk = true;
  234. parse_info.branch_info.ignore = false;
  235. parse_info.end_address = offset;
  236. return {ParseResult::ControlCaught, parse_info};
  237. }
  238. case OpCode::Id::KIL: {
  239. const auto pred_index = static_cast<u32>(instr.pred.pred_index);
  240. parse_info.branch_info.condition.predicate =
  241. GetPredicate(pred_index, instr.negate_pred != 0);
  242. if (parse_info.branch_info.condition.predicate == Pred::NeverExecute) {
  243. offset++;
  244. continue;
  245. }
  246. const ConditionCode cc = instr.flow_condition_code;
  247. parse_info.branch_info.condition.cc = cc;
  248. if (cc == ConditionCode::F) {
  249. offset++;
  250. continue;
  251. }
  252. parse_info.branch_info.address = exit_branch;
  253. parse_info.branch_info.kill = true;
  254. parse_info.branch_info.is_sync = false;
  255. parse_info.branch_info.is_brk = false;
  256. parse_info.branch_info.ignore = false;
  257. parse_info.end_address = offset;
  258. return {ParseResult::ControlCaught, parse_info};
  259. }
  260. case OpCode::Id::SSY: {
  261. const u32 target = offset + instr.bra.GetBranchTarget();
  262. insert_label(state, target);
  263. state.ssy_labels.emplace(offset, target);
  264. break;
  265. }
  266. case OpCode::Id::PBK: {
  267. const u32 target = offset + instr.bra.GetBranchTarget();
  268. insert_label(state, target);
  269. state.pbk_labels.emplace(offset, target);
  270. break;
  271. }
  272. case OpCode::Id::BRX: {
  273. return {ParseResult::AbnormalFlow, parse_info};
  274. }
  275. default:
  276. break;
  277. }
  278. offset++;
  279. }
  280. parse_info.branch_info.kill = false;
  281. parse_info.branch_info.is_sync = false;
  282. parse_info.branch_info.is_brk = false;
  283. parse_info.end_address = offset - 1;
  284. return {ParseResult::BlockEnd, parse_info};
  285. }
  286. bool TryInspectAddress(CFGRebuildState& state) {
  287. if (state.inspect_queries.empty()) {
  288. return false;
  289. }
  290. const u32 address = state.inspect_queries.front();
  291. state.inspect_queries.pop_front();
  292. const auto [result, block_index] = TryGetBlock(state, address);
  293. switch (result) {
  294. case BlockCollision::Found: {
  295. return true;
  296. }
  297. case BlockCollision::Inside: {
  298. // This case is the tricky one:
  299. // We need to Split the block in 2 sepparate blocks
  300. const u32 end = state.block_info[block_index].end;
  301. BlockInfo& new_block = CreateBlockInfo(state, address, end);
  302. BlockInfo& current_block = state.block_info[block_index];
  303. current_block.end = address - 1;
  304. new_block.branch = current_block.branch;
  305. BlockBranchInfo forward_branch{};
  306. forward_branch.address = address;
  307. forward_branch.ignore = true;
  308. current_block.branch = forward_branch;
  309. return true;
  310. }
  311. default:
  312. break;
  313. }
  314. const auto [parse_result, parse_info] = ParseCode(state, address);
  315. if (parse_result == ParseResult::AbnormalFlow) {
  316. // if it's AbnormalFlow, we end it as false, ending the CFG reconstruction
  317. return false;
  318. }
  319. BlockInfo& block_info = CreateBlockInfo(state, address, parse_info.end_address);
  320. block_info.branch = parse_info.branch_info;
  321. if (parse_info.branch_info.condition.IsUnconditional()) {
  322. return true;
  323. }
  324. const u32 fallthrough_address = parse_info.end_address + 1;
  325. state.inspect_queries.push_front(fallthrough_address);
  326. return true;
  327. }
  328. bool TryQuery(CFGRebuildState& state) {
  329. const auto gather_labels = [](std::stack<u32>& cc, std::map<u32, u32>& labels,
  330. BlockInfo& block) {
  331. auto gather_start = labels.lower_bound(block.start);
  332. const auto gather_end = labels.upper_bound(block.end);
  333. while (gather_start != gather_end) {
  334. cc.push(gather_start->second);
  335. ++gather_start;
  336. }
  337. };
  338. if (state.queries.empty()) {
  339. return false;
  340. }
  341. Query& q = state.queries.front();
  342. const u32 block_index = state.registered[q.address];
  343. BlockInfo& block = state.block_info[block_index];
  344. // If the block is visited, check if the stacks match, else gather the ssy/pbk
  345. // labels into the current stack and look if the branch at the end of the block
  346. // consumes a label. Schedule new queries accordingly
  347. if (block.visited) {
  348. BlockStack& stack = state.stacks[q.address];
  349. const bool all_okay = (stack.ssy_stack.empty() || q.ssy_stack == stack.ssy_stack) &&
  350. (stack.pbk_stack.empty() || q.pbk_stack == stack.pbk_stack);
  351. state.queries.pop_front();
  352. return all_okay;
  353. }
  354. block.visited = true;
  355. state.stacks.insert_or_assign(q.address, BlockStack{q});
  356. Query q2(q);
  357. state.queries.pop_front();
  358. gather_labels(q2.ssy_stack, state.ssy_labels, block);
  359. gather_labels(q2.pbk_stack, state.pbk_labels, block);
  360. if (!block.branch.condition.IsUnconditional()) {
  361. q2.address = block.end + 1;
  362. state.queries.push_back(q2);
  363. }
  364. Query conditional_query{q2};
  365. if (block.branch.is_sync) {
  366. if (block.branch.address == unassigned_branch) {
  367. block.branch.address = conditional_query.ssy_stack.top();
  368. }
  369. conditional_query.ssy_stack.pop();
  370. }
  371. if (block.branch.is_brk) {
  372. if (block.branch.address == unassigned_branch) {
  373. block.branch.address = conditional_query.pbk_stack.top();
  374. }
  375. conditional_query.pbk_stack.pop();
  376. }
  377. conditional_query.address = block.branch.address;
  378. state.queries.push_back(std::move(conditional_query));
  379. return true;
  380. }
  381. } // Anonymous namespace
  382. void InsertBranch(ASTManager& mm, const BlockBranchInfo& branch) {
  383. const auto get_expr = ([&](const Condition& cond) -> Expr {
  384. Expr result{};
  385. if (cond.cc != ConditionCode::T) {
  386. result = MakeExpr<ExprCondCode>(cond.cc);
  387. }
  388. if (cond.predicate != Pred::UnusedIndex) {
  389. u32 pred = static_cast<u32>(cond.predicate);
  390. bool negate = false;
  391. if (pred > 7) {
  392. negate = true;
  393. pred -= 8;
  394. }
  395. Expr extra = MakeExpr<ExprPredicate>(pred);
  396. if (negate) {
  397. extra = MakeExpr<ExprNot>(extra);
  398. }
  399. if (result) {
  400. return MakeExpr<ExprAnd>(extra, result);
  401. }
  402. return extra;
  403. }
  404. if (result) {
  405. return result;
  406. }
  407. return MakeExpr<ExprBoolean>(true);
  408. });
  409. if (branch.address < 0) {
  410. if (branch.kill) {
  411. mm.InsertReturn(get_expr(branch.condition), true);
  412. return;
  413. }
  414. mm.InsertReturn(get_expr(branch.condition), false);
  415. return;
  416. }
  417. mm.InsertGoto(get_expr(branch.condition), branch.address);
  418. }
  419. void DecompileShader(CFGRebuildState& state) {
  420. state.manager->Init();
  421. for (auto label : state.labels) {
  422. state.manager->DeclareLabel(label);
  423. }
  424. for (auto& block : state.block_info) {
  425. if (state.labels.count(block.start) != 0) {
  426. state.manager->InsertLabel(block.start);
  427. }
  428. u32 end = block.branch.ignore ? block.end + 1 : block.end;
  429. state.manager->InsertBlock(block.start, end);
  430. if (!block.branch.ignore) {
  431. InsertBranch(*state.manager, block.branch);
  432. }
  433. }
  434. state.manager->Decompile();
  435. }
  436. std::unique_ptr<ShaderCharacteristics> ScanFlow(const ProgramCode& program_code, u32 program_size,
  437. u32 start_address,
  438. const CompilerSettings& settings) {
  439. auto result_out = std::make_unique<ShaderCharacteristics>();
  440. if (settings.depth == CompileDepth::BruteForce) {
  441. result_out->settings.depth = CompileDepth::BruteForce;
  442. return result_out;
  443. }
  444. CFGRebuildState state{program_code, program_size, start_address};
  445. // Inspect Code and generate blocks
  446. state.labels.clear();
  447. state.labels.emplace(start_address);
  448. state.inspect_queries.push_back(state.start);
  449. while (!state.inspect_queries.empty()) {
  450. if (!TryInspectAddress(state)) {
  451. result_out->settings.depth = CompileDepth::BruteForce;
  452. return result_out;
  453. }
  454. }
  455. bool use_flow_stack = true;
  456. bool decompiled = false;
  457. if (settings.depth != CompileDepth::FlowStack) {
  458. // Decompile Stacks
  459. state.queries.push_back(Query{state.start, {}, {}});
  460. decompiled = true;
  461. while (!state.queries.empty()) {
  462. if (!TryQuery(state)) {
  463. decompiled = false;
  464. break;
  465. }
  466. }
  467. }
  468. use_flow_stack = !decompiled;
  469. // Sort and organize results
  470. std::sort(state.block_info.begin(), state.block_info.end(),
  471. [](const BlockInfo& a, const BlockInfo& b) -> bool { return a.start < b.start; });
  472. if (decompiled && settings.depth != CompileDepth::NoFlowStack) {
  473. ASTManager manager{settings.depth != CompileDepth::DecompileBackwards,
  474. settings.disable_else_derivation};
  475. state.manager = &manager;
  476. DecompileShader(state);
  477. decompiled = state.manager->IsFullyDecompiled();
  478. if (!decompiled) {
  479. if (settings.depth == CompileDepth::FullDecompile) {
  480. LOG_CRITICAL(HW_GPU, "Failed to remove all the gotos!:");
  481. } else {
  482. LOG_CRITICAL(HW_GPU, "Failed to remove all backward gotos!:");
  483. }
  484. state.manager->ShowCurrentState("Of Shader");
  485. state.manager->Clear();
  486. } else {
  487. auto characteristics = std::make_unique<ShaderCharacteristics>();
  488. characteristics->start = start_address;
  489. characteristics->settings.depth = settings.depth;
  490. characteristics->manager = std::move(manager);
  491. characteristics->end = state.block_info.back().end + 1;
  492. return characteristics;
  493. }
  494. }
  495. result_out->start = start_address;
  496. result_out->settings.depth =
  497. use_flow_stack ? CompileDepth::FlowStack : CompileDepth::NoFlowStack;
  498. result_out->blocks.clear();
  499. for (auto& block : state.block_info) {
  500. ShaderBlock new_block{};
  501. new_block.start = block.start;
  502. new_block.end = block.end;
  503. new_block.ignore_branch = block.branch.ignore;
  504. if (!new_block.ignore_branch) {
  505. new_block.branch.cond = block.branch.condition;
  506. new_block.branch.kills = block.branch.kill;
  507. new_block.branch.address = block.branch.address;
  508. }
  509. result_out->end = std::max(result_out->end, block.end);
  510. result_out->blocks.push_back(new_block);
  511. }
  512. if (!use_flow_stack) {
  513. result_out->labels = std::move(state.labels);
  514. return result_out;
  515. }
  516. auto back = result_out->blocks.begin();
  517. auto next = std::next(back);
  518. while (next != result_out->blocks.end()) {
  519. if (state.labels.count(next->start) == 0 && next->start == back->end + 1) {
  520. back->end = next->end;
  521. next = result_out->blocks.erase(next);
  522. continue;
  523. }
  524. back = next;
  525. ++next;
  526. }
  527. return result_out;
  528. }
  529. } // namespace VideoCommon::Shader