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;
40   CostState State;
41 
42   void propagateState(const InstructionCost &RHS) {
43     if (RHS.State == Invalid)
44       State = Invalid;
45   }
46 
47 public:
48   InstructionCost() = default;
49 
50   InstructionCost(CostState) = delete;
51   InstructionCost(CostType Val) : Value(Val), State(Valid) {}
52 
53   static InstructionCost getInvalid(CostType Val = 0) {
54     InstructionCost Tmp(Val);
55     Tmp.setInvalid();
56     return Tmp;
57   }
58 
59   bool isValid() const { return State == Valid; }
60   void setValid() { State = Valid; }
61   void setInvalid() { State = Invalid; }
62   CostState getState() const { return State; }
63 
64   /// This function is intended to be used as sparingly as possible, since the
65   /// class provides the full range of operator support required for arithmetic
66   /// and comparisons.
67   Optional<CostType> getValue() const {
68     if (isValid())
69       return Value;
70     return None;
71   }
72 
73   /// For all of the arithmetic operators provided here any invalid state is
74   /// perpetuated and cannot be removed. Once a cost becomes invalid it stays
75   /// invalid, and it also inherits any invalid state from the RHS. Regardless
76   /// of the state, arithmetic and comparisons work on the actual values in the
77   /// same way as they would on a basic type, such as integer.
78 
79   InstructionCost &operator+=(const InstructionCost &RHS) {
80     propagateState(RHS);
81     Value += RHS.Value;
82     return *this;
83   }
84 
85   InstructionCost &operator+=(const CostType RHS) {
86     InstructionCost RHS2(RHS);
87     *this += RHS2;
88     return *this;
89   }
90 
91   InstructionCost &operator-=(const InstructionCost &RHS) {
92     propagateState(RHS);
93     Value -= RHS.Value;
94     return *this;
95   }
96 
97   InstructionCost &operator-=(const CostType RHS) {
98     InstructionCost RHS2(RHS);
99     *this -= RHS2;
100     return *this;
101   }
102 
103   InstructionCost &operator*=(const InstructionCost &RHS) {
104     propagateState(RHS);
105     Value *= RHS.Value;
106     return *this;
107   }
108 
109   InstructionCost &operator*=(const CostType RHS) {
110     InstructionCost RHS2(RHS);
111     *this *= RHS2;
112     return *this;
113   }
114 
115   InstructionCost &operator/=(const InstructionCost &RHS) {
116     propagateState(RHS);
117     Value /= RHS.Value;
118     return *this;
119   }
120 
121   InstructionCost &operator/=(const CostType RHS) {
122     InstructionCost RHS2(RHS);
123     *this /= RHS2;
124     return *this;
125   }
126 
127   InstructionCost &operator++() {
128     *this += 1;
129     return *this;
130   }
131 
132   InstructionCost operator++(int) {
133     InstructionCost Copy = *this;
134     ++*this;
135     return Copy;
136   }
137 
138   InstructionCost &operator--() {
139     *this -= 1;
140     return *this;
141   }
142 
143   InstructionCost operator--(int) {
144     InstructionCost Copy = *this;
145     --*this;
146     return Copy;
147   }
148 
149   bool operator==(const InstructionCost &RHS) const {
150     return State == RHS.State && Value == RHS.Value;
151   }
152 
153   bool operator!=(const InstructionCost &RHS) const { return !(*this == RHS); }
154 
155   bool operator==(const CostType RHS) const {
156     return State == Valid && Value == RHS;
157   }
158 
159   bool operator!=(const CostType RHS) const { return !(*this == RHS); }
160 
161   /// For the comparison operators we have chosen to use total ordering with
162   /// the following rules:
163   ///  1. If either of the states != Valid then a lexicographical order is
164   ///     applied based upon the state.
165   ///  2. If both states are valid then order based upon value.
166   /// This avoids having to add asserts the comparison operators that the states
167   /// are valid and users can test for validity of the cost explicitly.
168   bool operator<(const InstructionCost &RHS) const {
169     if (State != Valid || RHS.State != Valid)
170       return State < RHS.State;
171     return Value < RHS.Value;
172   }
173 
174   bool operator>(const InstructionCost &RHS) const { return RHS < *this; }
175 
176   bool operator<=(const InstructionCost &RHS) const { return !(RHS < *this); }
177 
178   bool operator>=(const InstructionCost &RHS) const { return !(*this < RHS); }
179 
180   bool operator<(const CostType RHS) const {
181     InstructionCost RHS2(RHS);
182     return *this < RHS2;
183   }
184 
185   bool operator>(const CostType RHS) const {
186     InstructionCost RHS2(RHS);
187     return *this > RHS2;
188   }
189 
190   bool operator<=(const CostType RHS) const {
191     InstructionCost RHS2(RHS);
192     return *this <= RHS2;
193   }
194 
195   bool operator>=(const CostType RHS) const {
196     InstructionCost RHS2(RHS);
197     return *this >= RHS2;
198   }
199 
200   void print(raw_ostream &OS) const;
201 };
202 
203 inline InstructionCost operator+(const InstructionCost &LHS,
204                                  const InstructionCost &RHS) {
205   InstructionCost LHS2(LHS);
206   LHS2 += RHS;
207   return LHS2;
208 }
209 
210 inline InstructionCost operator-(const InstructionCost &LHS,
211                                  const InstructionCost &RHS) {
212   InstructionCost LHS2(LHS);
213   LHS2 -= RHS;
214   return LHS2;
215 }
216 
217 inline InstructionCost operator*(const InstructionCost &LHS,
218                                  const InstructionCost &RHS) {
219   InstructionCost LHS2(LHS);
220   LHS2 *= RHS;
221   return LHS2;
222 }
223 
224 inline InstructionCost operator/(const InstructionCost &LHS,
225                                  const InstructionCost &RHS) {
226   InstructionCost LHS2(LHS);
227   LHS2 /= RHS;
228   return LHS2;
229 }
230 
231 inline raw_ostream &operator<<(raw_ostream &OS, const InstructionCost &V) {
232   V.print(OS);
233   return OS;
234 }
235 
236 } // namespace llvm
237 
238 #endif
239