1 /*========================== begin_copyright_notice ============================ 2 3 Copyright (C) 2017-2021 Intel Corporation 4 5 SPDX-License-Identifier: MIT 6 7 ============================= end_copyright_notice ===========================*/ 8 9 #pragma once 10 11 #include "Compiler/CISACodeGen/CISACodeGen.h" 12 #include "Compiler/CISACodeGen/WIAnalysis.hpp" 13 #include "common/LLVMWarningsPush.hpp" 14 #include <llvm/ADT/StringRef.h> 15 #include <llvm/Support/Allocator.h> 16 #include "common/LLVMWarningsPop.hpp" 17 #include "Probe/Assertion.h" 18 #include <cstdint> 19 #include <string> 20 #include <sstream> 21 22 namespace IGC { 23 #if defined(_DEBUG) || defined(_INTERNAL) 24 #define IGC_MAP_LLVM_NAMES_TO_VISA 25 #endif 26 27 // A data type to track a variable's LLVM symbol name conditionally. 28 // The intent is zero overhead on release builds, but otherwise 29 // enable name tracking in release-internal or debug builds. 30 class CName { 31 #ifdef IGC_MAP_LLVM_NAMES_TO_VISA 32 // NOTE: if CVariable/CName's exist past the length of the underlying 33 // LLVM, then we should use a std::string or something else. 34 std::string value; 35 #else 36 // to give struct non-zero size; use a different name for this 37 // than 'value' so someone doesn't accidentially reference it. 38 char dummy_value; 39 #endif 40 public: 41 // Constructor to tell vISA to create the name 42 // Prefer the value CName::NONE. CName()43 CName() : CName(nullptr) { } 44 45 CName(const CName &) = default; 46 CName(const std::string & arg)47 CName(const std::string &arg) 48 #ifdef IGC_MAP_LLVM_NAMES_TO_VISA 49 : value(arg) 50 #endif 51 { } 52 CName(const llvm::StringRef & arg)53 CName(const llvm::StringRef &arg) 54 #ifdef IGC_MAP_LLVM_NAMES_TO_VISA 55 : value(arg.str()) 56 #endif 57 { } 58 59 // explicit: some compilers are very liberal about what can be a 60 // const char *; make sure the user really means it 61 CName(int) = delete; 62 CName(bool) = delete; 63 CName(const char * arg)64 CName(const char *arg) 65 #ifdef IGC_MAP_LLVM_NAMES_TO_VISA 66 : value(arg == nullptr ? "" : arg) 67 #endif 68 { } 69 70 // For split variables 71 // For example, an LLVM instruction split for 64b into two halves 72 // might use the names: 73 // ... CName(llvmValue->getName(), "Lo32") 74 // ... CName(llvmValue->getName(), "Hi32") CName(const CName & prefix,const char * suffix)75 CName(const CName &prefix, const char *suffix) 76 #ifdef IGC_MAP_LLVM_NAMES_TO_VISA 77 : CName(prefix.value + suffix) 78 #endif 79 { 80 } 81 82 // For instance variables: 83 // e.g. for (i = 0; ...) ... CName("inputVar", i) CName(const CName & prefix,int suffix)84 CName(const CName &prefix, int suffix) 85 #ifdef IGC_MAP_LLVM_NAMES_TO_VISA 86 { 87 std::stringstream ss; 88 ss << prefix.value << "_" << suffix; 89 value = ss.str(); 90 } 91 #else 92 { 93 } 94 #endif 95 getVisaCString() const96 const char *getVisaCString() const { 97 #ifdef IGC_MAP_LLVM_NAMES_TO_VISA 98 return value.empty() ? nullptr : value.c_str(); 99 #else 100 return nullptr; // tells vISA to allocate the name automatically 101 #endif 102 } 103 104 // like above but returns empty string if LLVM names are disabled getCString() const105 const char *getCString() const { 106 return getVisaCString() != nullptr ? getVisaCString() : ""; 107 } 108 empty() const109 bool empty() const {return size() == 0;} 110 size() const111 size_t size() const { 112 #ifdef IGC_MAP_LLVM_NAMES_TO_VISA 113 return value.size(); 114 #else 115 return 0; 116 #endif 117 } 118 119 // A constant used to represent a name without a special name 120 // Use this value when you want vISA to allocate an automatic name. 121 static const CName NONE; 122 }; 123 124 // As uniform is splitted into multiple ones, CVariable ctor's boolean uniform 125 // arg need changing. To avoid large changes, UniformArgWrap is used to allow 126 // both bool (existing one) or the newer WIBaseClass::WIDependancy to pass 127 // into CVariable's ctor. When boolean is no longer passed in, this wrap class 128 // should be removed. 129 class UniformArgWrap { 130 public: 131 WIBaseClass::WIDependancy m_dep; 132 UniformArgWrap()133 UniformArgWrap() : m_dep(WIBaseClass::RANDOM) {} UniformArgWrap(WIBaseClass::WIDependancy d)134 UniformArgWrap(WIBaseClass::WIDependancy d) : m_dep(d) {} UniformArgWrap(bool b)135 UniformArgWrap(bool b) : m_dep(b ? WIBaseClass::UNIFORM_THREAD : WIBaseClass::RANDOM) {} 136 }; 137 138 ///----------------------------------------------------------------------------- 139 /// CVariable 140 ///----------------------------------------------------------------------------- 141 class CVariable { 142 // immediate or undef value 143 CVariable(uint64_t immediate, VISA_Type type, uint16_t nbElem, bool undef); 144 public: 145 #if defined(_DEBUG) || defined(_INTERNAL) operator new(size_t size,llvm::SpecificBumpPtrAllocator<CVariable> & Allocator)146 void* operator new(size_t size, llvm::SpecificBumpPtrAllocator<CVariable> &Allocator) 147 { 148 return Allocator.Allocate(size / sizeof(CVariable)); 149 } 150 operator delete(void *,llvm::SpecificBumpPtrAllocator<CVariable> &)151 void operator delete(void*, llvm::SpecificBumpPtrAllocator<CVariable>&) {} 152 #endif 153 // immediate variable 154 CVariable(uint64_t immediate, VISA_Type type); 155 156 // undef variable 157 // these are represented as immediate but can considered as trash data 158 CVariable(VISA_Type type); 159 160 // alias variable; if numElements is 0, this is an alias to the whole 161 // variable, otherwise it's only to a part of it. 162 CVariable( 163 CVariable* var, VISA_Type type, uint16_t offset, 164 uint16_t numElements, UniformArgWrap uniform); 165 166 // general variable 167 CVariable( 168 uint16_t nbElement, 169 UniformArgWrap uniform, 170 VISA_Type type, 171 e_varType varType, 172 e_alignment align, 173 bool vectorUniform, 174 uint16_t numberInstance, 175 const CName &name); 176 177 // Copy Ctor CVariable(const CVariable & V)178 CVariable(const CVariable& V) : 179 m_immediateValue(V.m_immediateValue), 180 m_alias(nullptr), 181 m_nbElement(V.m_nbElement), 182 m_aliasOffset(0), 183 m_numberOfInstance(V.m_numberOfInstance), 184 m_type(V.m_type), 185 m_varType(V.m_varType), 186 m_align(V.m_align), 187 m_uniform(V.m_uniform), 188 m_isImmediate(V.m_isImmediate), 189 m_subspanUse(V.m_subspanUse), 190 m_uniformVector(V.m_uniformVector), 191 m_undef(V.m_undef), 192 m_isUnpacked(V.m_isUnpacked), 193 m_llvmName(V.m_llvmName) 194 { 195 } 196 GetAlign() const197 e_alignment GetAlign() const 198 { 199 IGC_ASSERT_MESSAGE(!m_isImmediate, "Calling GetAlign() on an immediate returns undefined result"); 200 return m_align; 201 } SetAlign(e_alignment thisAlign)202 void SetAlign(e_alignment thisAlign) { m_align = thisAlign; } 203 GetNumberElement() const204 uint16_t GetNumberElement() const { return m_nbElement; } IsUniform() const205 bool IsUniform() const { return WIAnalysis::isDepUniform(m_uniform); } // uniform_thread or above IsWorkGroupOrGlobalUniform() const206 bool IsWorkGroupOrGlobalUniform() const { return IsWorkGroupUniform() || IsGlobalUniform(); } IsWorkGroupUniform() const207 bool IsWorkGroupUniform() const { return m_uniform == WIBaseClass::UNIFORM_WORKGROUP; } IsGlobalUniform() const208 bool IsGlobalUniform() const { return m_uniform == WIBaseClass::UNIFORM_GLOBAL; } 209 GetSize() const210 uint GetSize() const { return m_nbElement * GetCISADataTypeSize(m_type); } GetElemSize() const211 uint GetElemSize() const { return GetCISADataTypeSize(m_type); } 212 GetAlias() const213 CVariable* GetAlias() const { return m_alias; } GetAliasOffset() const214 uint16_t GetAliasOffset() const { return m_aliasOffset; } GetType() const215 VISA_Type GetType() const { return m_type; } GetVarType() const216 e_varType GetVarType() const { return m_varType; } GetImmediateValue() const217 uint64_t GetImmediateValue() const 218 { 219 IGC_ASSERT(IsImmediate()); 220 return m_immediateValue; 221 } IsImmediate() const222 bool IsImmediate() const 223 { 224 IGC_ASSERT_MESSAGE((!m_isImmediate || (m_isImmediate && IsGlobalUniform())), 225 "IsImmediate => IsUniform invariant broken"); 226 return m_isImmediate; 227 } IsVectorUniform() const228 bool IsVectorUniform() const { return m_uniformVector; } GetNumberInstance() const229 uint8_t GetNumberInstance() const { return m_numberOfInstance; } IsUndef() const230 bool IsUndef() const { return m_undef; } setisUnpacked()231 void setisUnpacked() { m_isUnpacked = true; } isUnpacked()232 bool isUnpacked() { return m_isUnpacked; } getOffsetMultiplier() const233 uint8_t getOffsetMultiplier() const { return m_isUnpacked ? 2 : 1; } 234 void ResolveAlias(); 235 236 union { 237 VISA_GenVar* visaGenVariable[2]{ nullptr, nullptr }; 238 VISA_SurfaceVar* visaSurfVariable; 239 VISA_PredVar* visaPredVariable; 240 VISA_AddrVar* visaAddrVariable; 241 VISA_SamplerVar* visaSamplerVariable; 242 }; 243 getAlignment(unsigned off)244 static inline e_alignment getAlignment(unsigned off) 245 { 246 switch (off) 247 { 248 case 1: return EALIGN_BYTE; 249 case 2: return EALIGN_WORD; 250 case 4: return EALIGN_DWORD; 251 case 8: return EALIGN_QWORD; 252 case 16: return EALIGN_OWORD; 253 case 32: return EALIGN_HWORD; 254 case 64: return EALIGN_32WORD; 255 case 128: return EALIGN_64WORD; 256 default: 257 break; 258 } 259 260 return EALIGN_BYTE; 261 } 262 263 // Returns a best-effort LLVM name that this variable corresponds to 264 // It is not necessarily unique since LLVM variables may be split 265 // into multiple CVariable (as well as other ambiguities). 266 // Names are only non-empty in non-release builds. 267 // 268 // The vISA backend will suffix variable names to keep them 269 // unique. getName() const270 const CName &getName() const { 271 return m_llvmName; 272 } 273 // This accesses the name via a const char *. This will return 274 // nullptr if names are not tracked (e.g. release build). getVisaCString() const275 const char *getVisaCString() const { 276 if (IGC_IS_FLAG_ENABLED(UseVISAVarNames)) 277 return nullptr; 278 return m_llvmName.getVisaCString(); 279 } 280 281 void print(llvm::raw_ostream& OS) const; 282 283 void dump() const; 284 285 // ToDo: move them elsewhere? getVarTypeStr(e_varType varTy)286 static constexpr const char* getVarTypeStr(e_varType varTy) 287 { 288 switch (varTy) 289 { 290 case EVARTYPE_GENERAL: return "general"; 291 case EVARTYPE_ADDRESS: return "address"; 292 case EVARTYPE_PREDICATE: return "predicate"; 293 case EVARTYPE_SURFACE: return "surface"; 294 case EVARTYPE_SAMPLER: return "sampler"; 295 default: return "illegal"; 296 } 297 } getVISATypeStr(VISA_Type ty)298 static constexpr const char* getVISATypeStr(VISA_Type ty) 299 { 300 switch (ty) 301 { 302 case ISA_TYPE_UD: return "ud"; 303 case ISA_TYPE_D: return "d"; 304 case ISA_TYPE_UW: return "uw"; 305 case ISA_TYPE_W: return "w"; 306 case ISA_TYPE_UB: return "ub"; 307 case ISA_TYPE_B: return "b"; 308 case ISA_TYPE_DF: return "df"; 309 case ISA_TYPE_F: return "f"; 310 case ISA_TYPE_V: return "v"; 311 case ISA_TYPE_VF: return "vf"; 312 case ISA_TYPE_BOOL: return "bool"; 313 case ISA_TYPE_UQ: return "uq"; 314 case ISA_TYPE_Q: return "q"; 315 case ISA_TYPE_UV: return "uv"; 316 case ISA_TYPE_HF: return "hf"; 317 case ISA_TYPE_BF: return "bf"; 318 default: return "illegal"; 319 } 320 } 321 static uint GetCISADataTypeSize(VISA_Type type); 322 static e_alignment GetCISADataTypeAlignment(VISA_Type type); 323 324 private: 325 const uint64_t m_immediateValue; 326 327 CVariable* m_alias; 328 329 uint16_t m_nbElement; 330 uint16_t m_aliasOffset; 331 332 const uint8_t m_numberOfInstance; 333 const VISA_Type m_type; 334 const e_varType m_varType; 335 e_alignment m_align; 336 const WIBaseClass::WIDependancy m_uniform; 337 338 const unsigned char m_isImmediate : 1; 339 const unsigned char m_subspanUse : 1; 340 const unsigned char m_uniformVector : 1; 341 const unsigned char m_undef : 1; 342 343 // unpacked means the layout of the vector is stored as unpacked half 344 unsigned char m_isUnpacked : 1; 345 346 CName m_llvmName; 347 }; 348 349 } // namespace IGC 350