InstructionCost.h 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. //===- InstructionCost.h ----------------------------------------*- C++ -*-===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. /// \file
  9. /// This file defines an InstructionCost class that is used when calculating
  10. /// the cost of an instruction, or a group of instructions. In addition to a
  11. /// numeric value representing the cost the class also contains a state that
  12. /// can be used to encode particular properties, i.e. a cost being invalid or
  13. /// unknown.
  14. ///
  15. //===----------------------------------------------------------------------===//
  16. #ifndef LLVM_SUPPORT_INSTRUCTIONCOST_H
  17. #define LLVM_SUPPORT_INSTRUCTIONCOST_H
  18. #include "llvm/ADT/Optional.h"
  19. namespace llvm {
  20. class raw_ostream;
  21. class InstructionCost {
  22. public:
  23. using CostType = int;
  24. /// These states can currently be used to indicate whether a cost is valid or
  25. /// invalid. Examples of an invalid cost might be where the cost is
  26. /// prohibitively expensive and the user wants to prevent certain
  27. /// optimizations being performed. Or perhaps the cost is simply unknown
  28. /// because the operation makes no sense in certain circumstances. These
  29. /// states can be expanded in future to support other cases if necessary.
  30. enum CostState { Valid, Invalid };
  31. private:
  32. CostType Value = 0;
  33. CostState State = Valid;
  34. void propagateState(const InstructionCost &RHS) {
  35. if (RHS.State == Invalid)
  36. State = Invalid;
  37. }
  38. public:
  39. // A default constructed InstructionCost is a valid zero cost
  40. InstructionCost() = default;
  41. InstructionCost(CostState) = delete;
  42. InstructionCost(CostType Val) : Value(Val), State(Valid) {}
  43. static InstructionCost getInvalid(CostType Val = 0) {
  44. InstructionCost Tmp(Val);
  45. Tmp.setInvalid();
  46. return Tmp;
  47. }
  48. bool isValid() const { return State == Valid; }
  49. void setValid() { State = Valid; }
  50. void setInvalid() { State = Invalid; }
  51. CostState getState() const { return State; }
  52. /// This function is intended to be used as sparingly as possible, since the
  53. /// class provides the full range of operator support required for arithmetic
  54. /// and comparisons.
  55. Optional<CostType> getValue() const {
  56. if (isValid())
  57. return Value;
  58. return None;
  59. }
  60. /// For all of the arithmetic operators provided here any invalid state is
  61. /// perpetuated and cannot be removed. Once a cost becomes invalid it stays
  62. /// invalid, and it also inherits any invalid state from the RHS. Regardless
  63. /// of the state, arithmetic and comparisons work on the actual values in the
  64. /// same way as they would on a basic type, such as integer.
  65. InstructionCost &operator+=(const InstructionCost &RHS) {
  66. propagateState(RHS);
  67. Value += RHS.Value;
  68. return *this;
  69. }
  70. InstructionCost &operator+=(const CostType RHS) {
  71. InstructionCost RHS2(RHS);
  72. *this += RHS2;
  73. return *this;
  74. }
  75. InstructionCost &operator-=(const InstructionCost &RHS) {
  76. propagateState(RHS);
  77. Value -= RHS.Value;
  78. return *this;
  79. }
  80. InstructionCost &operator-=(const CostType RHS) {
  81. InstructionCost RHS2(RHS);
  82. *this -= RHS2;
  83. return *this;
  84. }
  85. InstructionCost &operator*=(const InstructionCost &RHS) {
  86. propagateState(RHS);
  87. Value *= RHS.Value;
  88. return *this;
  89. }
  90. InstructionCost &operator*=(const CostType RHS) {
  91. InstructionCost RHS2(RHS);
  92. *this *= RHS2;
  93. return *this;
  94. }
  95. InstructionCost &operator/=(const InstructionCost &RHS) {
  96. propagateState(RHS);
  97. Value /= RHS.Value;
  98. return *this;
  99. }
  100. InstructionCost &operator/=(const CostType RHS) {
  101. InstructionCost RHS2(RHS);
  102. *this /= RHS2;
  103. return *this;
  104. }
  105. InstructionCost &operator++() {
  106. *this += 1;
  107. return *this;
  108. }
  109. InstructionCost operator++(int) {
  110. InstructionCost Copy = *this;
  111. ++*this;
  112. return Copy;
  113. }
  114. InstructionCost &operator--() {
  115. *this -= 1;
  116. return *this;
  117. }
  118. InstructionCost operator--(int) {
  119. InstructionCost Copy = *this;
  120. --*this;
  121. return Copy;
  122. }
  123. /// For the comparison operators we have chosen to use lexicographical
  124. /// ordering where valid costs are always considered to be less than invalid
  125. /// costs. This avoids having to add asserts to the comparison operators that
  126. /// the states are valid and users can test for validity of the cost
  127. /// explicitly.
  128. bool operator<(const InstructionCost &RHS) const {
  129. if (State != RHS.State)
  130. return State < RHS.State;
  131. return Value < RHS.Value;
  132. }
  133. // Implement in terms of operator< to ensure that the two comparisons stay in
  134. // sync
  135. bool operator==(const InstructionCost &RHS) const {
  136. return !(*this < RHS) && !(RHS < *this);
  137. }
  138. bool operator!=(const InstructionCost &RHS) const { return !(*this == RHS); }
  139. bool operator==(const CostType RHS) const {
  140. InstructionCost RHS2(RHS);
  141. return *this == RHS2;
  142. }
  143. bool operator!=(const CostType RHS) const { return !(*this == RHS); }
  144. bool operator>(const InstructionCost &RHS) const { return RHS < *this; }
  145. bool operator<=(const InstructionCost &RHS) const { return !(RHS < *this); }
  146. bool operator>=(const InstructionCost &RHS) const { return !(*this < RHS); }
  147. bool operator<(const CostType RHS) const {
  148. InstructionCost RHS2(RHS);
  149. return *this < RHS2;
  150. }
  151. bool operator>(const CostType RHS) const {
  152. InstructionCost RHS2(RHS);
  153. return *this > RHS2;
  154. }
  155. bool operator<=(const CostType RHS) const {
  156. InstructionCost RHS2(RHS);
  157. return *this <= RHS2;
  158. }
  159. bool operator>=(const CostType RHS) const {
  160. InstructionCost RHS2(RHS);
  161. return *this >= RHS2;
  162. }
  163. void print(raw_ostream &OS) const;
  164. template <class Function>
  165. auto map(const Function &F) const -> InstructionCost {
  166. if (isValid())
  167. return F(*getValue());
  168. return getInvalid();
  169. }
  170. };
  171. inline InstructionCost operator+(const InstructionCost &LHS,
  172. const InstructionCost &RHS) {
  173. InstructionCost LHS2(LHS);
  174. LHS2 += RHS;
  175. return LHS2;
  176. }
  177. inline InstructionCost operator-(const InstructionCost &LHS,
  178. const InstructionCost &RHS) {
  179. InstructionCost LHS2(LHS);
  180. LHS2 -= RHS;
  181. return LHS2;
  182. }
  183. inline InstructionCost operator*(const InstructionCost &LHS,
  184. const InstructionCost &RHS) {
  185. InstructionCost LHS2(LHS);
  186. LHS2 *= RHS;
  187. return LHS2;
  188. }
  189. inline InstructionCost operator/(const InstructionCost &LHS,
  190. const InstructionCost &RHS) {
  191. InstructionCost LHS2(LHS);
  192. LHS2 /= RHS;
  193. return LHS2;
  194. }
  195. inline raw_ostream &operator<<(raw_ostream &OS, const InstructionCost &V) {
  196. V.print(OS);
  197. return OS;
  198. }
  199. } // namespace llvm
  200. #endif