1*0fca6ea1SDimitry Andric //===--- InfoByHwMode.h -----------------------------------------*- C++ -*-===// 2*0fca6ea1SDimitry Andric // 3*0fca6ea1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0fca6ea1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0fca6ea1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0fca6ea1SDimitry Andric // 7*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===// 8*0fca6ea1SDimitry Andric // Classes that implement data parameterized by HW modes for instruction 9*0fca6ea1SDimitry Andric // selection. Currently it is ValueTypeByHwMode (parameterized ValueType), 10*0fca6ea1SDimitry Andric // and RegSizeInfoByHwMode (parameterized register/spill size and alignment 11*0fca6ea1SDimitry Andric // data). 12*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===// 13*0fca6ea1SDimitry Andric 14*0fca6ea1SDimitry Andric #ifndef LLVM_UTILS_TABLEGEN_INFOBYHWMODE_H 15*0fca6ea1SDimitry Andric #define LLVM_UTILS_TABLEGEN_INFOBYHWMODE_H 16*0fca6ea1SDimitry Andric 17*0fca6ea1SDimitry Andric #include "CodeGenHwModes.h" 18*0fca6ea1SDimitry Andric #include "llvm/ADT/SmallVector.h" 19*0fca6ea1SDimitry Andric #include "llvm/ADT/StringRef.h" 20*0fca6ea1SDimitry Andric #include "llvm/CodeGenTypes/MachineValueType.h" 21*0fca6ea1SDimitry Andric #include "llvm/Support/Compiler.h" 22*0fca6ea1SDimitry Andric #include <cassert> 23*0fca6ea1SDimitry Andric #include <limits> 24*0fca6ea1SDimitry Andric #include <map> 25*0fca6ea1SDimitry Andric #include <string> 26*0fca6ea1SDimitry Andric #include <tuple> 27*0fca6ea1SDimitry Andric #include <utility> 28*0fca6ea1SDimitry Andric 29*0fca6ea1SDimitry Andric namespace llvm { 30*0fca6ea1SDimitry Andric 31*0fca6ea1SDimitry Andric class Record; 32*0fca6ea1SDimitry Andric class raw_ostream; 33*0fca6ea1SDimitry Andric 34*0fca6ea1SDimitry Andric template <typename InfoT> struct InfoByHwMode; 35*0fca6ea1SDimitry Andric 36*0fca6ea1SDimitry Andric std::string getModeName(unsigned Mode); 37*0fca6ea1SDimitry Andric 38*0fca6ea1SDimitry Andric enum : unsigned { 39*0fca6ea1SDimitry Andric DefaultMode = CodeGenHwModes::DefaultMode, 40*0fca6ea1SDimitry Andric }; 41*0fca6ea1SDimitry Andric 42*0fca6ea1SDimitry Andric template <typename InfoT> 43*0fca6ea1SDimitry Andric void union_modes(const InfoByHwMode<InfoT> &A, const InfoByHwMode<InfoT> &B, 44*0fca6ea1SDimitry Andric SmallVectorImpl<unsigned> &Modes) { 45*0fca6ea1SDimitry Andric auto AI = A.begin(); 46*0fca6ea1SDimitry Andric auto BI = B.begin(); 47*0fca6ea1SDimitry Andric 48*0fca6ea1SDimitry Andric // Skip default mode, but remember if we had one. 49*0fca6ea1SDimitry Andric bool HasDefault = false; 50*0fca6ea1SDimitry Andric if (AI != A.end() && AI->first == DefaultMode) { 51*0fca6ea1SDimitry Andric HasDefault = true; 52*0fca6ea1SDimitry Andric ++AI; 53*0fca6ea1SDimitry Andric } 54*0fca6ea1SDimitry Andric if (BI != B.end() && BI->first == DefaultMode) { 55*0fca6ea1SDimitry Andric HasDefault = true; 56*0fca6ea1SDimitry Andric ++BI; 57*0fca6ea1SDimitry Andric } 58*0fca6ea1SDimitry Andric 59*0fca6ea1SDimitry Andric while (AI != A.end()) { 60*0fca6ea1SDimitry Andric // If we're done with B, finish A. 61*0fca6ea1SDimitry Andric if (BI == B.end()) { 62*0fca6ea1SDimitry Andric for (; AI != A.end(); ++AI) 63*0fca6ea1SDimitry Andric Modes.push_back(AI->first); 64*0fca6ea1SDimitry Andric break; 65*0fca6ea1SDimitry Andric } 66*0fca6ea1SDimitry Andric 67*0fca6ea1SDimitry Andric if (BI->first < AI->first) { 68*0fca6ea1SDimitry Andric Modes.push_back(BI->first); 69*0fca6ea1SDimitry Andric ++BI; 70*0fca6ea1SDimitry Andric } else { 71*0fca6ea1SDimitry Andric Modes.push_back(AI->first); 72*0fca6ea1SDimitry Andric if (AI->first == BI->first) 73*0fca6ea1SDimitry Andric ++BI; 74*0fca6ea1SDimitry Andric ++AI; 75*0fca6ea1SDimitry Andric } 76*0fca6ea1SDimitry Andric } 77*0fca6ea1SDimitry Andric 78*0fca6ea1SDimitry Andric // Finish B. 79*0fca6ea1SDimitry Andric for (; BI != B.end(); ++BI) 80*0fca6ea1SDimitry Andric Modes.push_back(BI->first); 81*0fca6ea1SDimitry Andric 82*0fca6ea1SDimitry Andric // Make sure that the default mode is last on the list. 83*0fca6ea1SDimitry Andric if (HasDefault) 84*0fca6ea1SDimitry Andric Modes.push_back(DefaultMode); 85*0fca6ea1SDimitry Andric } 86*0fca6ea1SDimitry Andric 87*0fca6ea1SDimitry Andric template <typename InfoT> struct InfoByHwMode { 88*0fca6ea1SDimitry Andric typedef std::map<unsigned, InfoT> MapType; 89*0fca6ea1SDimitry Andric typedef typename MapType::value_type PairType; 90*0fca6ea1SDimitry Andric typedef typename MapType::iterator iterator; 91*0fca6ea1SDimitry Andric typedef typename MapType::const_iterator const_iterator; 92*0fca6ea1SDimitry Andric 93*0fca6ea1SDimitry Andric InfoByHwMode() = default; 94*0fca6ea1SDimitry Andric InfoByHwMode(const MapType &M) : Map(M) {} 95*0fca6ea1SDimitry Andric 96*0fca6ea1SDimitry Andric LLVM_ATTRIBUTE_ALWAYS_INLINE 97*0fca6ea1SDimitry Andric iterator begin() { return Map.begin(); } 98*0fca6ea1SDimitry Andric LLVM_ATTRIBUTE_ALWAYS_INLINE 99*0fca6ea1SDimitry Andric iterator end() { return Map.end(); } 100*0fca6ea1SDimitry Andric LLVM_ATTRIBUTE_ALWAYS_INLINE 101*0fca6ea1SDimitry Andric const_iterator begin() const { return Map.begin(); } 102*0fca6ea1SDimitry Andric LLVM_ATTRIBUTE_ALWAYS_INLINE 103*0fca6ea1SDimitry Andric const_iterator end() const { return Map.end(); } 104*0fca6ea1SDimitry Andric LLVM_ATTRIBUTE_ALWAYS_INLINE 105*0fca6ea1SDimitry Andric bool empty() const { return Map.empty(); } 106*0fca6ea1SDimitry Andric 107*0fca6ea1SDimitry Andric LLVM_ATTRIBUTE_ALWAYS_INLINE 108*0fca6ea1SDimitry Andric bool hasMode(unsigned M) const { return Map.find(M) != Map.end(); } 109*0fca6ea1SDimitry Andric LLVM_ATTRIBUTE_ALWAYS_INLINE 110*0fca6ea1SDimitry Andric bool hasDefault() const { 111*0fca6ea1SDimitry Andric return !Map.empty() && Map.begin()->first == DefaultMode; 112*0fca6ea1SDimitry Andric } 113*0fca6ea1SDimitry Andric 114*0fca6ea1SDimitry Andric InfoT &get(unsigned Mode) { 115*0fca6ea1SDimitry Andric auto F = Map.find(Mode); 116*0fca6ea1SDimitry Andric if (F != Map.end()) 117*0fca6ea1SDimitry Andric return F->second; 118*0fca6ea1SDimitry Andric 119*0fca6ea1SDimitry Andric // Copy and insert the default mode which should be first. 120*0fca6ea1SDimitry Andric assert(hasDefault()); 121*0fca6ea1SDimitry Andric auto P = Map.insert({Mode, Map.begin()->second}); 122*0fca6ea1SDimitry Andric return P.first->second; 123*0fca6ea1SDimitry Andric } 124*0fca6ea1SDimitry Andric const InfoT &get(unsigned Mode) const { 125*0fca6ea1SDimitry Andric auto F = Map.find(Mode); 126*0fca6ea1SDimitry Andric if (F != Map.end()) 127*0fca6ea1SDimitry Andric return F->second; 128*0fca6ea1SDimitry Andric // Get the default mode which should be first. 129*0fca6ea1SDimitry Andric F = Map.begin(); 130*0fca6ea1SDimitry Andric assert(F != Map.end() && F->first == DefaultMode); 131*0fca6ea1SDimitry Andric return F->second; 132*0fca6ea1SDimitry Andric } 133*0fca6ea1SDimitry Andric 134*0fca6ea1SDimitry Andric LLVM_ATTRIBUTE_ALWAYS_INLINE 135*0fca6ea1SDimitry Andric bool isSimple() const { 136*0fca6ea1SDimitry Andric return Map.size() == 1 && Map.begin()->first == DefaultMode; 137*0fca6ea1SDimitry Andric } 138*0fca6ea1SDimitry Andric LLVM_ATTRIBUTE_ALWAYS_INLINE 139*0fca6ea1SDimitry Andric const InfoT &getSimple() const { 140*0fca6ea1SDimitry Andric assert(isSimple()); 141*0fca6ea1SDimitry Andric return Map.begin()->second; 142*0fca6ea1SDimitry Andric } 143*0fca6ea1SDimitry Andric void makeSimple(unsigned Mode) { 144*0fca6ea1SDimitry Andric assert(hasMode(Mode) || hasDefault()); 145*0fca6ea1SDimitry Andric InfoT I = get(Mode); 146*0fca6ea1SDimitry Andric Map.clear(); 147*0fca6ea1SDimitry Andric Map.insert(std::pair(DefaultMode, I)); 148*0fca6ea1SDimitry Andric } 149*0fca6ea1SDimitry Andric 150*0fca6ea1SDimitry Andric protected: 151*0fca6ea1SDimitry Andric MapType Map; 152*0fca6ea1SDimitry Andric }; 153*0fca6ea1SDimitry Andric 154*0fca6ea1SDimitry Andric struct ValueTypeByHwMode : public InfoByHwMode<MVT> { 155*0fca6ea1SDimitry Andric ValueTypeByHwMode(Record *R, const CodeGenHwModes &CGH); 156*0fca6ea1SDimitry Andric ValueTypeByHwMode(Record *R, MVT T); 157*0fca6ea1SDimitry Andric ValueTypeByHwMode(MVT T) { Map.insert({DefaultMode, T}); } 158*0fca6ea1SDimitry Andric ValueTypeByHwMode() = default; 159*0fca6ea1SDimitry Andric 160*0fca6ea1SDimitry Andric bool operator==(const ValueTypeByHwMode &T) const; 161*0fca6ea1SDimitry Andric bool operator<(const ValueTypeByHwMode &T) const; 162*0fca6ea1SDimitry Andric 163*0fca6ea1SDimitry Andric bool isValid() const { return !Map.empty(); } 164*0fca6ea1SDimitry Andric MVT getType(unsigned Mode) const { return get(Mode); } 165*0fca6ea1SDimitry Andric MVT &getOrCreateTypeForMode(unsigned Mode, MVT Type); 166*0fca6ea1SDimitry Andric 167*0fca6ea1SDimitry Andric static StringRef getMVTName(MVT T); 168*0fca6ea1SDimitry Andric void writeToStream(raw_ostream &OS) const; 169*0fca6ea1SDimitry Andric void dump() const; 170*0fca6ea1SDimitry Andric 171*0fca6ea1SDimitry Andric unsigned PtrAddrSpace = std::numeric_limits<unsigned>::max(); 172*0fca6ea1SDimitry Andric bool isPointer() const { 173*0fca6ea1SDimitry Andric return PtrAddrSpace != std::numeric_limits<unsigned>::max(); 174*0fca6ea1SDimitry Andric } 175*0fca6ea1SDimitry Andric }; 176*0fca6ea1SDimitry Andric 177*0fca6ea1SDimitry Andric ValueTypeByHwMode getValueTypeByHwMode(Record *Rec, const CodeGenHwModes &CGH); 178*0fca6ea1SDimitry Andric 179*0fca6ea1SDimitry Andric raw_ostream &operator<<(raw_ostream &OS, const ValueTypeByHwMode &T); 180*0fca6ea1SDimitry Andric 181*0fca6ea1SDimitry Andric struct RegSizeInfo { 182*0fca6ea1SDimitry Andric unsigned RegSize; 183*0fca6ea1SDimitry Andric unsigned SpillSize; 184*0fca6ea1SDimitry Andric unsigned SpillAlignment; 185*0fca6ea1SDimitry Andric 186*0fca6ea1SDimitry Andric RegSizeInfo(Record *R); 187*0fca6ea1SDimitry Andric RegSizeInfo() = default; 188*0fca6ea1SDimitry Andric bool operator<(const RegSizeInfo &I) const; 189*0fca6ea1SDimitry Andric bool operator==(const RegSizeInfo &I) const { 190*0fca6ea1SDimitry Andric return std::tie(RegSize, SpillSize, SpillAlignment) == 191*0fca6ea1SDimitry Andric std::tie(I.RegSize, I.SpillSize, I.SpillAlignment); 192*0fca6ea1SDimitry Andric } 193*0fca6ea1SDimitry Andric bool operator!=(const RegSizeInfo &I) const { return !(*this == I); } 194*0fca6ea1SDimitry Andric 195*0fca6ea1SDimitry Andric bool isSubClassOf(const RegSizeInfo &I) const; 196*0fca6ea1SDimitry Andric void writeToStream(raw_ostream &OS) const; 197*0fca6ea1SDimitry Andric }; 198*0fca6ea1SDimitry Andric 199*0fca6ea1SDimitry Andric struct RegSizeInfoByHwMode : public InfoByHwMode<RegSizeInfo> { 200*0fca6ea1SDimitry Andric RegSizeInfoByHwMode(Record *R, const CodeGenHwModes &CGH); 201*0fca6ea1SDimitry Andric RegSizeInfoByHwMode() = default; 202*0fca6ea1SDimitry Andric bool operator<(const RegSizeInfoByHwMode &VI) const; 203*0fca6ea1SDimitry Andric bool operator==(const RegSizeInfoByHwMode &VI) const; 204*0fca6ea1SDimitry Andric bool operator!=(const RegSizeInfoByHwMode &VI) const { 205*0fca6ea1SDimitry Andric return !(*this == VI); 206*0fca6ea1SDimitry Andric } 207*0fca6ea1SDimitry Andric 208*0fca6ea1SDimitry Andric bool isSubClassOf(const RegSizeInfoByHwMode &I) const; 209*0fca6ea1SDimitry Andric bool hasStricterSpillThan(const RegSizeInfoByHwMode &I) const; 210*0fca6ea1SDimitry Andric 211*0fca6ea1SDimitry Andric void writeToStream(raw_ostream &OS) const; 212*0fca6ea1SDimitry Andric 213*0fca6ea1SDimitry Andric void insertRegSizeForMode(unsigned Mode, RegSizeInfo Info) { 214*0fca6ea1SDimitry Andric Map.insert(std::pair(Mode, Info)); 215*0fca6ea1SDimitry Andric } 216*0fca6ea1SDimitry Andric }; 217*0fca6ea1SDimitry Andric 218*0fca6ea1SDimitry Andric raw_ostream &operator<<(raw_ostream &OS, const RegSizeInfo &T); 219*0fca6ea1SDimitry Andric raw_ostream &operator<<(raw_ostream &OS, const RegSizeInfoByHwMode &T); 220*0fca6ea1SDimitry Andric 221*0fca6ea1SDimitry Andric struct SubRegRange { 222*0fca6ea1SDimitry Andric uint16_t Size; 223*0fca6ea1SDimitry Andric uint16_t Offset; 224*0fca6ea1SDimitry Andric 225*0fca6ea1SDimitry Andric SubRegRange(Record *R); 226*0fca6ea1SDimitry Andric SubRegRange(uint16_t Size, uint16_t Offset) : Size(Size), Offset(Offset) {} 227*0fca6ea1SDimitry Andric }; 228*0fca6ea1SDimitry Andric 229*0fca6ea1SDimitry Andric struct SubRegRangeByHwMode : public InfoByHwMode<SubRegRange> { 230*0fca6ea1SDimitry Andric SubRegRangeByHwMode(Record *R, const CodeGenHwModes &CGH); 231*0fca6ea1SDimitry Andric SubRegRangeByHwMode(SubRegRange Range) { Map.insert({DefaultMode, Range}); } 232*0fca6ea1SDimitry Andric SubRegRangeByHwMode() = default; 233*0fca6ea1SDimitry Andric 234*0fca6ea1SDimitry Andric void insertSubRegRangeForMode(unsigned Mode, SubRegRange Info) { 235*0fca6ea1SDimitry Andric Map.insert(std::pair(Mode, Info)); 236*0fca6ea1SDimitry Andric } 237*0fca6ea1SDimitry Andric }; 238*0fca6ea1SDimitry Andric 239*0fca6ea1SDimitry Andric struct EncodingInfoByHwMode : public InfoByHwMode<Record *> { 240*0fca6ea1SDimitry Andric EncodingInfoByHwMode(Record *R, const CodeGenHwModes &CGH); 241*0fca6ea1SDimitry Andric EncodingInfoByHwMode() = default; 242*0fca6ea1SDimitry Andric }; 243*0fca6ea1SDimitry Andric 244*0fca6ea1SDimitry Andric } // namespace llvm 245*0fca6ea1SDimitry Andric 246*0fca6ea1SDimitry Andric #endif // LLVM_UTILS_TABLEGEN_INFOBYHWMODE_H 247