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