verification_pass.cpp 3.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include <map>
  4. #include <set>
  5. #include "shader_recompiler/exception.h"
  6. #include "shader_recompiler/frontend/ir/basic_block.h"
  7. #include "shader_recompiler/frontend/ir/value.h"
  8. #include "shader_recompiler/ir_opt/passes.h"
  9. namespace Shader::Optimization {
  10. static void ValidateTypes(const IR::Program& program) {
  11. for (const auto& block : program.blocks) {
  12. for (const IR::Inst& inst : *block) {
  13. if (inst.GetOpcode() == IR::Opcode::Phi) {
  14. // Skip validation on phi nodes
  15. continue;
  16. }
  17. const size_t num_args{inst.NumArgs()};
  18. for (size_t i = 0; i < num_args; ++i) {
  19. const IR::Type t1{inst.Arg(i).Type()};
  20. const IR::Type t2{IR::ArgTypeOf(inst.GetOpcode(), i)};
  21. if (!IR::AreTypesCompatible(t1, t2)) {
  22. throw LogicError("Invalid types in block:\n{}", IR::DumpBlock(*block));
  23. }
  24. }
  25. }
  26. }
  27. }
  28. static void ValidateUses(const IR::Program& program) {
  29. std::map<IR::Inst*, int> actual_uses;
  30. for (const auto& block : program.blocks) {
  31. for (const IR::Inst& inst : *block) {
  32. const size_t num_args{inst.NumArgs()};
  33. for (size_t i = 0; i < num_args; ++i) {
  34. const IR::Value arg{inst.Arg(i)};
  35. if (!arg.IsImmediate()) {
  36. ++actual_uses[arg.Inst()];
  37. }
  38. }
  39. }
  40. }
  41. for (const auto& [inst, uses] : actual_uses) {
  42. if (inst->UseCount() != uses) {
  43. throw LogicError("Invalid uses in block: {}", IR::DumpProgram(program));
  44. }
  45. }
  46. }
  47. static void ValidateForwardDeclarations(const IR::Program& program) {
  48. std::set<const IR::Inst*> definitions;
  49. for (const IR::Block* const block : program.blocks) {
  50. for (const IR::Inst& inst : *block) {
  51. definitions.emplace(&inst);
  52. if (inst.GetOpcode() == IR::Opcode::Phi) {
  53. // Phi nodes can have forward declarations
  54. continue;
  55. }
  56. const size_t num_args{inst.NumArgs()};
  57. for (size_t arg = 0; arg < num_args; ++arg) {
  58. if (inst.Arg(arg).IsImmediate()) {
  59. continue;
  60. }
  61. if (!definitions.contains(inst.Arg(arg).Inst())) {
  62. throw LogicError("Forward declaration in block: {}", IR::DumpBlock(*block));
  63. }
  64. }
  65. }
  66. }
  67. }
  68. static void ValidatePhiNodes(const IR::Program& program) {
  69. for (const IR::Block* const block : program.blocks) {
  70. bool no_more_phis{false};
  71. for (const IR::Inst& inst : *block) {
  72. if (inst.GetOpcode() == IR::Opcode::Phi) {
  73. if (no_more_phis) {
  74. throw LogicError("Interleaved phi nodes: {}", IR::DumpBlock(*block));
  75. }
  76. } else {
  77. no_more_phis = true;
  78. }
  79. }
  80. }
  81. }
  82. void VerificationPass(const IR::Program& program) {
  83. ValidateTypes(program);
  84. ValidateUses(program);
  85. ValidateForwardDeclarations(program);
  86. ValidatePhiNodes(program);
  87. }
  88. } // namespace Shader::Optimization