const_folding_rules.h 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. // Copyright (c) 2018 Google LLC
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #ifndef SOURCE_OPT_CONST_FOLDING_RULES_H_
  15. #define SOURCE_OPT_CONST_FOLDING_RULES_H_
  16. #include <unordered_map>
  17. #include <vector>
  18. #include "source/opt/constants.h"
  19. namespace spvtools {
  20. namespace opt {
  21. // Constant Folding Rules:
  22. //
  23. // The folding mechanism is built around the concept of a |ConstantFoldingRule|.
  24. // A constant folding rule is a function that implements a method of simplifying
  25. // an instruction to a constant.
  26. //
  27. // The inputs to a folding rule are:
  28. // |inst| - the instruction to be simplified.
  29. // |constants| - if an in-operands is an id of a constant, then the
  30. // corresponding value in |constants| contains that
  31. // constant value. Otherwise, the corresponding entry in
  32. // |constants| is |nullptr|.
  33. //
  34. // A constant folding rule returns a pointer to an Constant if |inst| can be
  35. // simplified using this rule. Otherwise, it returns |nullptr|.
  36. //
  37. // See const_folding_rules.cpp for examples on how to write a constant folding
  38. // rule.
  39. //
  40. // Be sure to add new constant folding rules to the table of constant folding
  41. // rules in the constructor for ConstantFoldingRules. The new rule should be
  42. // added to the list for every opcode that it applies to. Note that earlier
  43. // rules in the list are given priority. That is, if an earlier rule is able to
  44. // fold an instruction, the later rules will not be attempted.
  45. using ConstantFoldingRule = std::function<const analysis::Constant*(
  46. IRContext* ctx, Instruction* inst,
  47. const std::vector<const analysis::Constant*>& constants)>;
  48. class ConstantFoldingRules {
  49. protected:
  50. // The |Key| and |Value| structs are used to by-pass a "decorated name length
  51. // exceeded, name was truncated" warning on VS2013 and VS2015.
  52. struct Key {
  53. uint32_t instruction_set;
  54. uint32_t opcode;
  55. };
  56. friend bool operator<(const Key& a, const Key& b) {
  57. if (a.instruction_set < b.instruction_set) {
  58. return true;
  59. }
  60. if (a.instruction_set > b.instruction_set) {
  61. return false;
  62. }
  63. return a.opcode < b.opcode;
  64. }
  65. struct Value {
  66. std::vector<ConstantFoldingRule> value;
  67. void push_back(ConstantFoldingRule rule) { value.push_back(rule); }
  68. };
  69. public:
  70. ConstantFoldingRules(IRContext* ctx) : context_(ctx) {}
  71. virtual ~ConstantFoldingRules() = default;
  72. // Returns true if there is at least 1 folding rule for |opcode|.
  73. bool HasFoldingRule(const Instruction* inst) const {
  74. return !GetRulesForInstruction(inst).empty();
  75. }
  76. // Returns true if there is at least 1 folding rule for |inst|.
  77. const std::vector<ConstantFoldingRule>& GetRulesForInstruction(
  78. const Instruction* inst) const {
  79. if (inst->opcode() != spv::Op::OpExtInst) {
  80. auto it = rules_.find(inst->opcode());
  81. if (it != rules_.end()) {
  82. return it->second.value;
  83. }
  84. } else {
  85. uint32_t ext_inst_id = inst->GetSingleWordInOperand(0);
  86. uint32_t ext_opcode = inst->GetSingleWordInOperand(1);
  87. auto it = ext_rules_.find({ext_inst_id, ext_opcode});
  88. if (it != ext_rules_.end()) {
  89. return it->second.value;
  90. }
  91. }
  92. return empty_vector_;
  93. }
  94. // Add the folding rules.
  95. virtual void AddFoldingRules();
  96. protected:
  97. struct hasher {
  98. size_t operator()(const spv::Op& op) const noexcept {
  99. return std::hash<uint32_t>()(uint32_t(op));
  100. }
  101. };
  102. // |rules[opcode]| is the set of rules that can be applied to instructions
  103. // with |opcode| as the opcode.
  104. std::unordered_map<spv::Op, Value, hasher> rules_;
  105. // The folding rules for extended instructions.
  106. std::map<Key, Value> ext_rules_;
  107. private:
  108. // The context that the instruction to be folded will be a part of.
  109. IRContext* context_;
  110. // The empty set of rules to be used as the default return value in
  111. // |GetRulesForInstruction|.
  112. std::vector<ConstantFoldingRule> empty_vector_;
  113. };
  114. } // namespace opt
  115. } // namespace spvtools
  116. #endif // SOURCE_OPT_CONST_FOLDING_RULES_H_