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 propagateState(const InstructionCost & RHS)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; InstructionCost(CostType Val)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 isValid()59 bool isValid() const { return State == Valid; } setValid()60 void setValid() { State = Valid; } setInvalid()61 void setInvalid() { State = Invalid; } getState()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. getValue()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