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