| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400 |
- // Copyright 2019 yuzu Emulator Project
- // Licensed under GPLv2 or any later version
- // Refer to the license.txt file included.
- #pragma once
- #include <functional>
- #include <list>
- #include <memory>
- #include <optional>
- #include <string>
- #include <unordered_map>
- #include <vector>
- #include "video_core/shader/expr.h"
- #include "video_core/shader/node.h"
- namespace VideoCommon::Shader {
- class ASTBase;
- class ASTBlockDecoded;
- class ASTBlockEncoded;
- class ASTBreak;
- class ASTDoWhile;
- class ASTGoto;
- class ASTIfElse;
- class ASTIfThen;
- class ASTLabel;
- class ASTProgram;
- class ASTReturn;
- class ASTVarSet;
- using ASTData = std::variant<ASTProgram, ASTIfThen, ASTIfElse, ASTBlockEncoded, ASTBlockDecoded,
- ASTVarSet, ASTGoto, ASTLabel, ASTDoWhile, ASTReturn, ASTBreak>;
- using ASTNode = std::shared_ptr<ASTBase>;
- enum class ASTZipperType : u32 {
- Program,
- IfThen,
- IfElse,
- Loop,
- };
- class ASTZipper final {
- public:
- explicit ASTZipper();
- void Init(ASTNode first, ASTNode parent);
- ASTNode GetFirst() const {
- return first;
- }
- ASTNode GetLast() const {
- return last;
- }
- void PushBack(ASTNode new_node);
- void PushFront(ASTNode new_node);
- void InsertAfter(ASTNode new_node, ASTNode at_node);
- void InsertBefore(ASTNode new_node, ASTNode at_node);
- void DetachTail(ASTNode node);
- void DetachSingle(ASTNode node);
- void DetachSegment(ASTNode start, ASTNode end);
- void Remove(ASTNode node);
- ASTNode first{};
- ASTNode last{};
- };
- class ASTProgram {
- public:
- ASTZipper nodes{};
- };
- class ASTIfThen {
- public:
- explicit ASTIfThen(Expr condition) : condition{std::move(condition)} {}
- Expr condition;
- ASTZipper nodes{};
- };
- class ASTIfElse {
- public:
- ASTZipper nodes{};
- };
- class ASTBlockEncoded {
- public:
- explicit ASTBlockEncoded(u32 start, u32 end) : start{start}, end{end} {}
- u32 start;
- u32 end;
- };
- class ASTBlockDecoded {
- public:
- explicit ASTBlockDecoded(NodeBlock&& new_nodes) : nodes(std::move(new_nodes)) {}
- NodeBlock nodes;
- };
- class ASTVarSet {
- public:
- explicit ASTVarSet(u32 index, Expr condition) : index{index}, condition{std::move(condition)} {}
- u32 index;
- Expr condition;
- };
- class ASTLabel {
- public:
- explicit ASTLabel(u32 index) : index{index} {}
- u32 index;
- bool unused{};
- };
- class ASTGoto {
- public:
- explicit ASTGoto(Expr condition, u32 label) : condition{std::move(condition)}, label{label} {}
- Expr condition;
- u32 label;
- };
- class ASTDoWhile {
- public:
- explicit ASTDoWhile(Expr condition) : condition{std::move(condition)} {}
- Expr condition;
- ASTZipper nodes{};
- };
- class ASTReturn {
- public:
- explicit ASTReturn(Expr condition, bool kills)
- : condition{std::move(condition)}, kills{kills} {}
- Expr condition;
- bool kills;
- };
- class ASTBreak {
- public:
- explicit ASTBreak(Expr condition) : condition{std::move(condition)} {}
- Expr condition;
- };
- class ASTBase {
- public:
- explicit ASTBase(ASTNode parent, ASTData data)
- : data{std::move(data)}, parent{std::move(parent)} {}
- template <class U, class... Args>
- static ASTNode Make(ASTNode parent, Args&&... args) {
- return std::make_shared<ASTBase>(std::move(parent),
- ASTData(U(std::forward<Args>(args)...)));
- }
- void SetParent(ASTNode new_parent) {
- parent = std::move(new_parent);
- }
- ASTNode& GetParent() {
- return parent;
- }
- const ASTNode& GetParent() const {
- return parent;
- }
- u32 GetLevel() const {
- u32 level = 0;
- auto next_parent = parent;
- while (next_parent) {
- next_parent = next_parent->GetParent();
- level++;
- }
- return level;
- }
- ASTData* GetInnerData() {
- return &data;
- }
- const ASTData* GetInnerData() const {
- return &data;
- }
- ASTNode GetNext() const {
- return next;
- }
- ASTNode GetPrevious() const {
- return previous;
- }
- ASTZipper& GetManager() {
- return *manager;
- }
- const ASTZipper& GetManager() const {
- return *manager;
- }
- std::optional<u32> GetGotoLabel() const {
- auto inner = std::get_if<ASTGoto>(&data);
- if (inner) {
- return {inner->label};
- }
- return {};
- }
- Expr GetGotoCondition() const {
- auto inner = std::get_if<ASTGoto>(&data);
- if (inner) {
- return inner->condition;
- }
- return nullptr;
- }
- void MarkLabelUnused() {
- auto inner = std::get_if<ASTLabel>(&data);
- if (inner) {
- inner->unused = true;
- }
- }
- bool IsLabelUnused() const {
- auto inner = std::get_if<ASTLabel>(&data);
- if (inner) {
- return inner->unused;
- }
- return true;
- }
- std::optional<u32> GetLabelIndex() const {
- auto inner = std::get_if<ASTLabel>(&data);
- if (inner) {
- return {inner->index};
- }
- return {};
- }
- Expr GetIfCondition() const {
- auto inner = std::get_if<ASTIfThen>(&data);
- if (inner) {
- return inner->condition;
- }
- return nullptr;
- }
- void SetGotoCondition(Expr new_condition) {
- auto inner = std::get_if<ASTGoto>(&data);
- if (inner) {
- inner->condition = std::move(new_condition);
- }
- }
- bool IsIfThen() const {
- return std::holds_alternative<ASTIfThen>(data);
- }
- bool IsIfElse() const {
- return std::holds_alternative<ASTIfElse>(data);
- }
- bool IsBlockEncoded() const {
- return std::holds_alternative<ASTBlockEncoded>(data);
- }
- void TransformBlockEncoded(NodeBlock&& nodes) {
- data = ASTBlockDecoded(std::move(nodes));
- }
- bool IsLoop() const {
- return std::holds_alternative<ASTDoWhile>(data);
- }
- ASTZipper* GetSubNodes() {
- if (std::holds_alternative<ASTProgram>(data)) {
- return &std::get_if<ASTProgram>(&data)->nodes;
- }
- if (std::holds_alternative<ASTIfThen>(data)) {
- return &std::get_if<ASTIfThen>(&data)->nodes;
- }
- if (std::holds_alternative<ASTIfElse>(data)) {
- return &std::get_if<ASTIfElse>(&data)->nodes;
- }
- if (std::holds_alternative<ASTDoWhile>(data)) {
- return &std::get_if<ASTDoWhile>(&data)->nodes;
- }
- return nullptr;
- }
- void Clear() {
- next.reset();
- previous.reset();
- parent.reset();
- manager = nullptr;
- }
- private:
- friend class ASTZipper;
- ASTData data;
- ASTNode parent{};
- ASTNode next{};
- ASTNode previous{};
- ASTZipper* manager{};
- };
- class ASTManager final {
- public:
- ASTManager(bool full_decompile, bool disable_else_derivation);
- ~ASTManager();
- ASTManager(const ASTManager& o) = delete;
- ASTManager& operator=(const ASTManager& other) = delete;
- ASTManager(ASTManager&& other) noexcept = default;
- ASTManager& operator=(ASTManager&& other) noexcept = default;
- void Init();
- void DeclareLabel(u32 address);
- void InsertLabel(u32 address);
- void InsertGoto(Expr condition, u32 address);
- void InsertBlock(u32 start_address, u32 end_address);
- void InsertReturn(Expr condition, bool kills);
- std::string Print();
- void Decompile();
- void ShowCurrentState(std::string_view state);
- void SanityCheck();
- void Clear();
- bool IsFullyDecompiled() const {
- if (full_decompile) {
- return gotos.empty();
- }
- for (ASTNode goto_node : gotos) {
- auto label_index = goto_node->GetGotoLabel();
- if (!label_index) {
- return false;
- }
- ASTNode glabel = labels[*label_index];
- if (IsBackwardsJump(goto_node, glabel)) {
- return false;
- }
- }
- return true;
- }
- ASTNode GetProgram() const {
- return main_node;
- }
- u32 GetVariables() const {
- return variables;
- }
- const std::vector<ASTNode>& GetLabels() const {
- return labels;
- }
- private:
- bool IsBackwardsJump(ASTNode goto_node, ASTNode label_node) const;
- bool IndirectlyRelated(const ASTNode& first, const ASTNode& second) const;
- bool DirectlyRelated(const ASTNode& first, const ASTNode& second) const;
- void EncloseDoWhile(ASTNode goto_node, ASTNode label);
- void EncloseIfThen(ASTNode goto_node, ASTNode label);
- void MoveOutward(ASTNode goto_node);
- u32 NewVariable() {
- return variables++;
- }
- bool full_decompile{};
- bool disable_else_derivation{};
- std::unordered_map<u32, u32> labels_map{};
- u32 labels_count{};
- std::vector<ASTNode> labels{};
- std::list<ASTNode> gotos{};
- u32 variables{};
- ASTProgram* program{};
- ASTNode main_node{};
- Expr false_condition{};
- };
- } // namespace VideoCommon::Shader
|