microinstruction.h 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. // Copyright 2021 yuzu Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #pragma once
  5. #include <array>
  6. #include <cstring>
  7. #include <type_traits>
  8. #include <utility>
  9. #include <vector>
  10. #include <boost/intrusive/list.hpp>
  11. #include "common/bit_cast.h"
  12. #include "common/common_types.h"
  13. #include "shader_recompiler/frontend/ir/opcodes.h"
  14. #include "shader_recompiler/frontend/ir/type.h"
  15. #include "shader_recompiler/frontend/ir/value.h"
  16. namespace Shader::IR {
  17. class Block;
  18. struct AssociatedInsts;
  19. class Inst : public boost::intrusive::list_base_hook<> {
  20. public:
  21. explicit Inst(Opcode op_, u32 flags_) noexcept;
  22. ~Inst();
  23. Inst& operator=(const Inst&) = delete;
  24. Inst(const Inst&) = delete;
  25. Inst& operator=(Inst&&) = delete;
  26. Inst(Inst&&) = delete;
  27. /// Get the number of uses this instruction has.
  28. [[nodiscard]] int UseCount() const noexcept {
  29. return use_count;
  30. }
  31. /// Determines whether this instruction has uses or not.
  32. [[nodiscard]] bool HasUses() const noexcept {
  33. return use_count > 0;
  34. }
  35. /// Get the opcode this microinstruction represents.
  36. [[nodiscard]] IR::Opcode Opcode() const noexcept {
  37. return op;
  38. }
  39. /// Determines if there is a pseudo-operation associated with this instruction.
  40. [[nodiscard]] bool HasAssociatedPseudoOperation() const noexcept {
  41. return associated_insts != nullptr;
  42. }
  43. /// Determines whether or not this instruction may have side effects.
  44. [[nodiscard]] bool MayHaveSideEffects() const noexcept;
  45. /// Determines whether or not this instruction is a pseudo-instruction.
  46. /// Pseudo-instructions depend on their parent instructions for their semantics.
  47. [[nodiscard]] bool IsPseudoInstruction() const noexcept;
  48. /// Determines if all arguments of this instruction are immediates.
  49. [[nodiscard]] bool AreAllArgsImmediates() const;
  50. /// Gets a pseudo-operation associated with this instruction
  51. [[nodiscard]] Inst* GetAssociatedPseudoOperation(IR::Opcode opcode);
  52. /// Get the type this instruction returns.
  53. [[nodiscard]] IR::Type Type() const;
  54. /// Get the number of arguments this instruction has.
  55. [[nodiscard]] size_t NumArgs() const;
  56. /// Get the value of a given argument index.
  57. [[nodiscard]] Value Arg(size_t index) const;
  58. /// Set the value of a given argument index.
  59. void SetArg(size_t index, Value value);
  60. /// Get a pointer to the block of a phi argument.
  61. [[nodiscard]] Block* PhiBlock(size_t index) const;
  62. /// Add phi operand to a phi instruction.
  63. void AddPhiOperand(Block* predecessor, const Value& value);
  64. void Invalidate();
  65. void ClearArgs();
  66. void ReplaceUsesWith(Value replacement);
  67. void ReplaceOpcode(IR::Opcode opcode);
  68. template <typename FlagsType>
  69. requires(sizeof(FlagsType) <= sizeof(u32) && std::is_trivially_copyable_v<FlagsType>)
  70. [[nodiscard]] FlagsType Flags() const noexcept {
  71. FlagsType ret;
  72. std::memcpy(&ret, &flags, sizeof(ret));
  73. return ret;
  74. }
  75. template <typename FlagsType>
  76. requires(sizeof(FlagsType) <= sizeof(u32) && std::is_trivially_copyable_v<FlagsType>)
  77. [[nodiscard]] void SetFlags(FlagsType& new_val) noexcept {
  78. std::memcpy(&flags, &new_val, sizeof(new_val));
  79. }
  80. /// Intrusively store the host definition of this instruction.
  81. template <typename DefinitionType>
  82. void SetDefinition(DefinitionType def) {
  83. definition = Common::BitCast<u32>(def);
  84. }
  85. /// Return the intrusively stored host definition of this instruction.
  86. template <typename DefinitionType>
  87. [[nodiscard]] DefinitionType Definition() const noexcept {
  88. return Common::BitCast<DefinitionType>(definition);
  89. }
  90. private:
  91. struct NonTriviallyDummy {
  92. NonTriviallyDummy() noexcept {}
  93. };
  94. void Use(const Value& value);
  95. void UndoUse(const Value& value);
  96. IR::Opcode op{};
  97. int use_count{};
  98. u32 flags{};
  99. u32 definition{};
  100. union {
  101. NonTriviallyDummy dummy{};
  102. std::vector<std::pair<Block*, Value>> phi_args;
  103. std::array<Value, 5> args;
  104. };
  105. std::unique_ptr<AssociatedInsts> associated_insts;
  106. };
  107. static_assert(sizeof(Inst) <= 128, "Inst size unintentionally increased");
  108. struct AssociatedInsts {
  109. union {
  110. Inst* in_bounds_inst;
  111. Inst* sparse_inst;
  112. Inst* zero_inst{};
  113. };
  114. Inst* sign_inst{};
  115. Inst* carry_inst{};
  116. Inst* overflow_inst{};
  117. };
  118. } // namespace Shader::IR