xref: /netbsd-src/external/apache2/llvm/dist/llvm/include/llvm/Support/InstructionCost.h (revision 82d56013d7b633d116a93943de88e08335357a7c)
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 
17 #ifndef LLVM_SUPPORT_INSTRUCTIONCOST_H
18 #define LLVM_SUPPORT_INSTRUCTIONCOST_H
19 
20 #include "llvm/ADT/Optional.h"
21 
22 namespace llvm {
23 
24 class raw_ostream;
25 
26 class InstructionCost {
27 public:
28   using CostType = int;
29 
30   /// These states can currently be used to indicate whether a cost is valid or
31   /// invalid. Examples of an invalid cost might be where the cost is
32   /// prohibitively expensive and the user wants to prevent certain
33   /// optimizations being performed. Or perhaps the cost is simply unknown
34   /// because the operation makes no sense in certain circumstances. These
35   /// states can be expanded in future to support other cases if necessary.
36   enum CostState { Valid, Invalid };
37 
38 private:
39   CostType Value = 0;
40   CostState State = Valid;
41 
propagateState(const InstructionCost & RHS)42   void propagateState(const InstructionCost &RHS) {
43     if (RHS.State == Invalid)
44       State = Invalid;
45   }
46 
47 public:
48   // A default constructed InstructionCost is a valid zero cost
49   InstructionCost() = default;
50 
51   InstructionCost(CostState) = delete;
InstructionCost(CostType Val)52   InstructionCost(CostType Val) : Value(Val), State(Valid) {}
53 
54   static InstructionCost getInvalid(CostType Val = 0) {
55     InstructionCost Tmp(Val);
56     Tmp.setInvalid();
57     return Tmp;
58   }
59 
isValid()60   bool isValid() const { return State == Valid; }
setValid()61   void setValid() { State = Valid; }
setInvalid()62   void setInvalid() { State = Invalid; }
getState()63   CostState getState() const { return State; }
64 
65   /// This function is intended to be used as sparingly as possible, since the
66   /// class provides the full range of operator support required for arithmetic
67   /// and comparisons.
getValue()68   Optional<CostType> getValue() const {
69     if (isValid())
70       return Value;
71     return None;
72   }
73 
74   /// For all of the arithmetic operators provided here any invalid state is
75   /// perpetuated and cannot be removed. Once a cost becomes invalid it stays
76   /// invalid, and it also inherits any invalid state from the RHS. Regardless
77   /// of the state, arithmetic and comparisons work on the actual values in the
78   /// same way as they would on a basic type, such as integer.
79 
80   InstructionCost &operator+=(const InstructionCost &RHS) {
81     propagateState(RHS);
82     Value += RHS.Value;
83     return *this;
84   }
85 
86   InstructionCost &operator+=(const CostType RHS) {
87     InstructionCost RHS2(RHS);
88     *this += RHS2;
89     return *this;
90   }
91 
92   InstructionCost &operator-=(const InstructionCost &RHS) {
93     propagateState(RHS);
94     Value -= RHS.Value;
95     return *this;
96   }
97 
98   InstructionCost &operator-=(const CostType RHS) {
99     InstructionCost RHS2(RHS);
100     *this -= RHS2;
101     return *this;
102   }
103 
104   InstructionCost &operator*=(const InstructionCost &RHS) {
105     propagateState(RHS);
106     Value *= RHS.Value;
107     return *this;
108   }
109 
110   InstructionCost &operator*=(const CostType RHS) {
111     InstructionCost RHS2(RHS);
112     *this *= RHS2;
113     return *this;
114   }
115 
116   InstructionCost &operator/=(const InstructionCost &RHS) {
117     propagateState(RHS);
118     Value /= RHS.Value;
119     return *this;
120   }
121 
122   InstructionCost &operator/=(const CostType RHS) {
123     InstructionCost RHS2(RHS);
124     *this /= RHS2;
125     return *this;
126   }
127 
128   InstructionCost &operator++() {
129     *this += 1;
130     return *this;
131   }
132 
133   InstructionCost operator++(int) {
134     InstructionCost Copy = *this;
135     ++*this;
136     return Copy;
137   }
138 
139   InstructionCost &operator--() {
140     *this -= 1;
141     return *this;
142   }
143 
144   InstructionCost operator--(int) {
145     InstructionCost Copy = *this;
146     --*this;
147     return Copy;
148   }
149 
150   /// For the comparison operators we have chosen to use lexicographical
151   /// ordering where valid costs are always considered to be less than invalid
152   /// costs. This avoids having to add asserts to the comparison operators that
153   /// the states are valid and users can test for validity of the cost
154   /// explicitly.
155   bool operator<(const InstructionCost &RHS) const {
156     if (State != RHS.State)
157       return State < RHS.State;
158     return Value < RHS.Value;
159   }
160 
161   // Implement in terms of operator< to ensure that the two comparisons stay in
162   // sync
163   bool operator==(const InstructionCost &RHS) const {
164     return !(*this < RHS) && !(RHS < *this);
165   }
166 
167   bool operator!=(const InstructionCost &RHS) const { return !(*this == RHS); }
168 
169   bool operator==(const CostType RHS) const {
170     InstructionCost RHS2(RHS);
171     return *this == RHS2;
172   }
173 
174   bool operator!=(const CostType RHS) const { return !(*this == RHS); }
175 
176   bool operator>(const InstructionCost &RHS) const { return RHS < *this; }
177 
178   bool operator<=(const InstructionCost &RHS) const { return !(RHS < *this); }
179 
180   bool operator>=(const InstructionCost &RHS) const { return !(*this < RHS); }
181 
182   bool operator<(const CostType RHS) const {
183     InstructionCost RHS2(RHS);
184     return *this < RHS2;
185   }
186 
187   bool operator>(const CostType RHS) const {
188     InstructionCost RHS2(RHS);
189     return *this > RHS2;
190   }
191 
192   bool operator<=(const CostType RHS) const {
193     InstructionCost RHS2(RHS);
194     return *this <= RHS2;
195   }
196 
197   bool operator>=(const CostType RHS) const {
198     InstructionCost RHS2(RHS);
199     return *this >= RHS2;
200   }
201 
202   void print(raw_ostream &OS) const;
203 
204   template <class Function>
205   auto map(const Function &F) const -> InstructionCost {
206     if (isValid())
207       return F(*getValue());
208     return getInvalid();
209   }
210 };
211 
212 inline InstructionCost operator+(const InstructionCost &LHS,
213                                  const InstructionCost &RHS) {
214   InstructionCost LHS2(LHS);
215   LHS2 += RHS;
216   return LHS2;
217 }
218 
219 inline InstructionCost operator-(const InstructionCost &LHS,
220                                  const InstructionCost &RHS) {
221   InstructionCost LHS2(LHS);
222   LHS2 -= RHS;
223   return LHS2;
224 }
225 
226 inline InstructionCost operator*(const InstructionCost &LHS,
227                                  const InstructionCost &RHS) {
228   InstructionCost LHS2(LHS);
229   LHS2 *= RHS;
230   return LHS2;
231 }
232 
233 inline InstructionCost operator/(const InstructionCost &LHS,
234                                  const InstructionCost &RHS) {
235   InstructionCost LHS2(LHS);
236   LHS2 /= RHS;
237   return LHS2;
238 }
239 
240 inline raw_ostream &operator<<(raw_ostream &OS, const InstructionCost &V) {
241   V.print(OS);
242   return OS;
243 }
244 
245 } // namespace llvm
246 
247 #endif
248