ast.h 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400
  1. // Copyright 2019 yuzu Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #pragma once
  5. #include <functional>
  6. #include <list>
  7. #include <memory>
  8. #include <optional>
  9. #include <string>
  10. #include <unordered_map>
  11. #include <vector>
  12. #include "video_core/shader/expr.h"
  13. #include "video_core/shader/node.h"
  14. namespace VideoCommon::Shader {
  15. class ASTBase;
  16. class ASTBlockDecoded;
  17. class ASTBlockEncoded;
  18. class ASTBreak;
  19. class ASTDoWhile;
  20. class ASTGoto;
  21. class ASTIfElse;
  22. class ASTIfThen;
  23. class ASTLabel;
  24. class ASTProgram;
  25. class ASTReturn;
  26. class ASTVarSet;
  27. using ASTData = std::variant<ASTProgram, ASTIfThen, ASTIfElse, ASTBlockEncoded, ASTBlockDecoded,
  28. ASTVarSet, ASTGoto, ASTLabel, ASTDoWhile, ASTReturn, ASTBreak>;
  29. using ASTNode = std::shared_ptr<ASTBase>;
  30. enum class ASTZipperType : u32 {
  31. Program,
  32. IfThen,
  33. IfElse,
  34. Loop,
  35. };
  36. class ASTZipper final {
  37. public:
  38. explicit ASTZipper();
  39. void Init(ASTNode first, ASTNode parent);
  40. ASTNode GetFirst() const {
  41. return first;
  42. }
  43. ASTNode GetLast() const {
  44. return last;
  45. }
  46. void PushBack(ASTNode new_node);
  47. void PushFront(ASTNode new_node);
  48. void InsertAfter(ASTNode new_node, ASTNode at_node);
  49. void InsertBefore(ASTNode new_node, ASTNode at_node);
  50. void DetachTail(ASTNode node);
  51. void DetachSingle(ASTNode node);
  52. void DetachSegment(ASTNode start, ASTNode end);
  53. void Remove(ASTNode node);
  54. ASTNode first{};
  55. ASTNode last{};
  56. };
  57. class ASTProgram {
  58. public:
  59. ASTZipper nodes{};
  60. };
  61. class ASTIfThen {
  62. public:
  63. explicit ASTIfThen(Expr condition) : condition{std::move(condition)} {}
  64. Expr condition;
  65. ASTZipper nodes{};
  66. };
  67. class ASTIfElse {
  68. public:
  69. ASTZipper nodes{};
  70. };
  71. class ASTBlockEncoded {
  72. public:
  73. explicit ASTBlockEncoded(u32 start, u32 end) : start{start}, end{end} {}
  74. u32 start;
  75. u32 end;
  76. };
  77. class ASTBlockDecoded {
  78. public:
  79. explicit ASTBlockDecoded(NodeBlock&& new_nodes) : nodes(std::move(new_nodes)) {}
  80. NodeBlock nodes;
  81. };
  82. class ASTVarSet {
  83. public:
  84. explicit ASTVarSet(u32 index, Expr condition) : index{index}, condition{std::move(condition)} {}
  85. u32 index;
  86. Expr condition;
  87. };
  88. class ASTLabel {
  89. public:
  90. explicit ASTLabel(u32 index) : index{index} {}
  91. u32 index;
  92. bool unused{};
  93. };
  94. class ASTGoto {
  95. public:
  96. explicit ASTGoto(Expr condition, u32 label) : condition{std::move(condition)}, label{label} {}
  97. Expr condition;
  98. u32 label;
  99. };
  100. class ASTDoWhile {
  101. public:
  102. explicit ASTDoWhile(Expr condition) : condition{std::move(condition)} {}
  103. Expr condition;
  104. ASTZipper nodes{};
  105. };
  106. class ASTReturn {
  107. public:
  108. explicit ASTReturn(Expr condition, bool kills)
  109. : condition{std::move(condition)}, kills{kills} {}
  110. Expr condition;
  111. bool kills;
  112. };
  113. class ASTBreak {
  114. public:
  115. explicit ASTBreak(Expr condition) : condition{std::move(condition)} {}
  116. Expr condition;
  117. };
  118. class ASTBase {
  119. public:
  120. explicit ASTBase(ASTNode parent, ASTData data)
  121. : data{std::move(data)}, parent{std::move(parent)} {}
  122. template <class U, class... Args>
  123. static ASTNode Make(ASTNode parent, Args&&... args) {
  124. return std::make_shared<ASTBase>(std::move(parent),
  125. ASTData(U(std::forward<Args>(args)...)));
  126. }
  127. void SetParent(ASTNode new_parent) {
  128. parent = std::move(new_parent);
  129. }
  130. ASTNode& GetParent() {
  131. return parent;
  132. }
  133. const ASTNode& GetParent() const {
  134. return parent;
  135. }
  136. u32 GetLevel() const {
  137. u32 level = 0;
  138. auto next_parent = parent;
  139. while (next_parent) {
  140. next_parent = next_parent->GetParent();
  141. level++;
  142. }
  143. return level;
  144. }
  145. ASTData* GetInnerData() {
  146. return &data;
  147. }
  148. const ASTData* GetInnerData() const {
  149. return &data;
  150. }
  151. ASTNode GetNext() const {
  152. return next;
  153. }
  154. ASTNode GetPrevious() const {
  155. return previous;
  156. }
  157. ASTZipper& GetManager() {
  158. return *manager;
  159. }
  160. const ASTZipper& GetManager() const {
  161. return *manager;
  162. }
  163. std::optional<u32> GetGotoLabel() const {
  164. auto inner = std::get_if<ASTGoto>(&data);
  165. if (inner) {
  166. return {inner->label};
  167. }
  168. return {};
  169. }
  170. Expr GetGotoCondition() const {
  171. auto inner = std::get_if<ASTGoto>(&data);
  172. if (inner) {
  173. return inner->condition;
  174. }
  175. return nullptr;
  176. }
  177. void MarkLabelUnused() {
  178. auto inner = std::get_if<ASTLabel>(&data);
  179. if (inner) {
  180. inner->unused = true;
  181. }
  182. }
  183. bool IsLabelUnused() const {
  184. auto inner = std::get_if<ASTLabel>(&data);
  185. if (inner) {
  186. return inner->unused;
  187. }
  188. return true;
  189. }
  190. std::optional<u32> GetLabelIndex() const {
  191. auto inner = std::get_if<ASTLabel>(&data);
  192. if (inner) {
  193. return {inner->index};
  194. }
  195. return {};
  196. }
  197. Expr GetIfCondition() const {
  198. auto inner = std::get_if<ASTIfThen>(&data);
  199. if (inner) {
  200. return inner->condition;
  201. }
  202. return nullptr;
  203. }
  204. void SetGotoCondition(Expr new_condition) {
  205. auto inner = std::get_if<ASTGoto>(&data);
  206. if (inner) {
  207. inner->condition = std::move(new_condition);
  208. }
  209. }
  210. bool IsIfThen() const {
  211. return std::holds_alternative<ASTIfThen>(data);
  212. }
  213. bool IsIfElse() const {
  214. return std::holds_alternative<ASTIfElse>(data);
  215. }
  216. bool IsBlockEncoded() const {
  217. return std::holds_alternative<ASTBlockEncoded>(data);
  218. }
  219. void TransformBlockEncoded(NodeBlock&& nodes) {
  220. data = ASTBlockDecoded(std::move(nodes));
  221. }
  222. bool IsLoop() const {
  223. return std::holds_alternative<ASTDoWhile>(data);
  224. }
  225. ASTZipper* GetSubNodes() {
  226. if (std::holds_alternative<ASTProgram>(data)) {
  227. return &std::get_if<ASTProgram>(&data)->nodes;
  228. }
  229. if (std::holds_alternative<ASTIfThen>(data)) {
  230. return &std::get_if<ASTIfThen>(&data)->nodes;
  231. }
  232. if (std::holds_alternative<ASTIfElse>(data)) {
  233. return &std::get_if<ASTIfElse>(&data)->nodes;
  234. }
  235. if (std::holds_alternative<ASTDoWhile>(data)) {
  236. return &std::get_if<ASTDoWhile>(&data)->nodes;
  237. }
  238. return nullptr;
  239. }
  240. void Clear() {
  241. next.reset();
  242. previous.reset();
  243. parent.reset();
  244. manager = nullptr;
  245. }
  246. private:
  247. friend class ASTZipper;
  248. ASTData data;
  249. ASTNode parent{};
  250. ASTNode next{};
  251. ASTNode previous{};
  252. ASTZipper* manager{};
  253. };
  254. class ASTManager final {
  255. public:
  256. ASTManager(bool full_decompile, bool disable_else_derivation);
  257. ~ASTManager();
  258. ASTManager(const ASTManager& o) = delete;
  259. ASTManager& operator=(const ASTManager& other) = delete;
  260. ASTManager(ASTManager&& other) noexcept = default;
  261. ASTManager& operator=(ASTManager&& other) noexcept = default;
  262. void Init();
  263. void DeclareLabel(u32 address);
  264. void InsertLabel(u32 address);
  265. void InsertGoto(Expr condition, u32 address);
  266. void InsertBlock(u32 start_address, u32 end_address);
  267. void InsertReturn(Expr condition, bool kills);
  268. std::string Print();
  269. void Decompile();
  270. void ShowCurrentState(std::string_view state);
  271. void SanityCheck();
  272. void Clear();
  273. bool IsFullyDecompiled() const {
  274. if (full_decompile) {
  275. return gotos.empty();
  276. }
  277. for (ASTNode goto_node : gotos) {
  278. auto label_index = goto_node->GetGotoLabel();
  279. if (!label_index) {
  280. return false;
  281. }
  282. ASTNode glabel = labels[*label_index];
  283. if (IsBackwardsJump(goto_node, glabel)) {
  284. return false;
  285. }
  286. }
  287. return true;
  288. }
  289. ASTNode GetProgram() const {
  290. return main_node;
  291. }
  292. u32 GetVariables() const {
  293. return variables;
  294. }
  295. const std::vector<ASTNode>& GetLabels() const {
  296. return labels;
  297. }
  298. private:
  299. bool IsBackwardsJump(ASTNode goto_node, ASTNode label_node) const;
  300. bool IndirectlyRelated(const ASTNode& first, const ASTNode& second) const;
  301. bool DirectlyRelated(const ASTNode& first, const ASTNode& second) const;
  302. void EncloseDoWhile(ASTNode goto_node, ASTNode label);
  303. void EncloseIfThen(ASTNode goto_node, ASTNode label);
  304. void MoveOutward(ASTNode goto_node);
  305. u32 NewVariable() {
  306. return variables++;
  307. }
  308. bool full_decompile{};
  309. bool disable_else_derivation{};
  310. std::unordered_map<u32, u32> labels_map{};
  311. u32 labels_count{};
  312. std::vector<ASTNode> labels{};
  313. std::list<ASTNode> gotos{};
  314. u32 variables{};
  315. ASTProgram* program{};
  316. ASTNode main_node{};
  317. Expr false_condition{};
  318. };
  319. } // namespace VideoCommon::Shader