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