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 | |
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; |
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 | |
60 | bool isValid() const { return State == Valid; } |
61 | void setValid() { State = Valid; } |
62 | void setInvalid() { State = Invalid; } |
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. |
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 | |