1 /*========================== begin_copyright_notice ============================ 2 3 Copyright (C) 2020-2021 Intel Corporation 4 5 SPDX-License-Identifier: MIT 6 7 ============================= end_copyright_notice ===========================*/ 8 9 #ifndef IGA_MESSAGE_INFO_HPP 10 #define IGA_MESSAGE_INFO_HPP 11 12 #include "../api/iga_bxml_enums.hpp" 13 #include "../Backend/Native/Field.hpp" 14 #include "../IR/Types.hpp" 15 #include "../IR/Loc.hpp" 16 17 #include <cstdint> 18 #include <string> 19 #include <tuple> 20 #include <vector> 21 22 namespace iga 23 { 24 struct DescField { DescFieldiga::DescField25 DescField(int _off, int _len) : off(_off), len(_len) { } 26 int off, len; 27 }; 28 29 using DiagnosticList = std::vector<std::pair<DescField,std::string>>; 30 using DecodedDescFields = 31 std::vector<std::tuple<Fragment,uint32_t,std::string>>; 32 33 // This is generic list of send operations. One or more messages may map 34 // to the same element (hence why "generic"). In other words, two 35 // different units (maybe different hardware generate the same message). 36 enum class SendOp { 37 INVALID, 38 #define DEFINE_SEND_OP(E, M, D, A) E, 39 #include "EnumSendOpInfo.hpp" 40 #undef DEFINE_SEND_OP 41 }; 42 43 struct SendOpDefinition { 44 SendOp op; 45 const char *mnemonic; // e.g. "load" for SendOp::LOAD 46 const char *description; // a longer freer description 47 48 // typesafe bitset of send op attributes 49 enum class Attr { 50 NONE = 0x0, 51 // 52 // the may have a destination (e.g. loads or atomics) 53 // certain control ops may or may not have destinations 54 HAS_DST = 0x1, 55 // 56 // is the address a scalar register (e.g. load_block) 57 IS_SCALAR_ADDR = 0x2, 58 // 59 // if the operation supports a ChMask (e.g. load_quad) 60 HAS_CMASK = 0x4, 61 // 62 // the op is a load, store, or atomic 63 GROUP_LOAD = 0x10, 64 GROUP_STORE = 0x20, 65 GROUP_ATOMIC = 0x40, 66 GROUP_OTHER = 0x80, // e.g. fence, barrier, etc... 67 68 // for atomics, the number of data arguments in src1 69 ATOMIC_UNARY = 0x100, // none (atomic_iinc) 70 ATOMIC_BINARY = 0x200, // one (atomic_fadd) 71 ATOMIC_TERNARY = 0x400, // two (atomic_icas) 72 }; 73 Attr attrs; 74 SendOpDefinitioniga::SendOpDefinition75 constexpr SendOpDefinition( 76 SendOp o, 77 const char *mne, 78 const char *desc, 79 Attr _attrs = Attr::NONE) 80 : op(o), mnemonic(mne), description(desc), attrs(_attrs) { } 81 constexpr SendOpDefinition(const SendOpDefinition&) = delete; 82 constexpr SendOpDefinition& operator=(const SendOpDefinition&) = delete; 83 isValidiga::SendOpDefinition84 bool isValid() const {return op != SendOp::INVALID;} hasAttriga::SendOpDefinition85 bool hasAttr(Attr a) const {return (((int)attrs & (int)a)) != 0;} 86 hasDstiga::SendOpDefinition87 bool hasDst() const {return hasAttr(Attr::HAS_DST);} hasChMaskiga::SendOpDefinition88 bool hasChMask() const {return hasAttr(Attr::HAS_CMASK);} isAddressScalariga::SendOpDefinition89 bool isAddressScalar() const {return hasAttr(Attr::IS_SCALAR_ADDR);} 90 isLoadiga::SendOpDefinition91 bool isLoad() const {return hasAttr(Attr::GROUP_LOAD);} isStoreiga::SendOpDefinition92 bool isStore() const {return hasAttr(Attr::GROUP_STORE);} isAtomiciga::SendOpDefinition93 bool isAtomic() const {return hasAttr(Attr::GROUP_ATOMIC);} isOtheriga::SendOpDefinition94 bool isOther() const {return hasAttr(Attr::GROUP_OTHER);} 95 numAtomicArgsiga::SendOpDefinition96 int numAtomicArgs() const { 97 return hasAttr(Attr::ATOMIC_UNARY) ? 0 : 98 hasAttr(Attr::ATOMIC_BINARY) ? 1 : 99 hasAttr(Attr::ATOMIC_TERNARY) ? 2 : 100 -1; 101 } 102 }; // SendOpDefinition operator |(SendOpDefinition::Attr a1,SendOpDefinition::Attr a2)103 static inline constexpr SendOpDefinition::Attr operator|( 104 SendOpDefinition::Attr a1, 105 SendOpDefinition::Attr a2) 106 { 107 return SendOpDefinition::Attr(int(a1) | int(a2)); 108 } 109 110 111 const SendOpDefinition &lookupSendOp(SendOp op); 112 const SendOpDefinition &lookupSendOp(const char *mnemonic); 113 114 std::string ToSyntax(SendOp op); 115 116 enum class CacheOpt { 117 // Invalid value (not invalidate or anything) 118 INVALID = 0, 119 // 120 // the default caching state from MOCS or wherever 121 DEFAULT, 122 // 123 // a read is the last use and the lines should be invalidated 124 // e.g. bit 13 in some HDC messages 125 READINVALIDATE, 126 // 127 // indicates a load should be cached 128 // 129 // e.g. in the BTI system 0xFD is used for this (non-coherent) 130 CACHED, 131 // 132 // indicates a message that bypasses the cache (and evicts the entry 133 // if present) 134 // 135 // e.g. in the BTI system 0xFF is used for this (coherent) 136 UNCACHED, 137 // 138 // a streaming access (line goes into LRU) 139 STREAMING, 140 // 141 // invalidates and writes back lines to the backing store 142 WRITEBACK, 143 // 144 // indicates lines should be written back to the backing store as well 145 // as retained in all levels 146 WRITETHROUGH, 147 }; 148 std::string ToSymbol(CacheOpt op); 149 150 enum class AddrType { 151 // the invalid value 152 INVALID = 0, 153 // stateless 154 FLAT, 155 // stateful: bindless surface state (UMD) 156 BSS, 157 // stateful: surface state (KMD) 158 SS, 159 // stateful: binding table interface 160 BTI, 161 }; 162 std::string ToSymbol(AddrType op); 163 164 /////////////////////////////////////////////////////////////////////////// 165 // Generic processing of basic buffer messages. This includes data port 166 // vector reads and writes as well block and atomic messages. There may be 167 // certain obscure or legacy operations that are unsupported. 168 // 169 struct MessageInfo { 170 enum class Attr : uint32_t { 171 NONE = 0x0, 172 // 173 // Set on atomic operations that return data 174 ATOMIC_RETURNS = 1 << 0, 175 // 176 // For messages that uncompress data, expand into the high unit 177 // instead of the low. 178 EXPAND_HIGH = 1 << 1, 179 // 180 // If the message supports a channel mask for vector size 181 // (data elements) 182 HAS_CHMASK = 1 << 2, 183 // 184 // Indicates the message is has U, V, R, and LOD coordinates 185 // as part of the address payloads. 186 HAS_UVRLOD = 1 << 3, 187 // 188 // Indicates a scratch message 189 SCRATCH = 1 << 4, 190 // 191 // Indicates SLM 192 SLM = 1 << 5, 193 // 194 // Indicates the data is transposed during load or store 195 TRANSPOSED = 1 << 6, 196 // 197 // Indicates the message is a typed operation 198 TYPED = 1 << 7, 199 // 200 VALID = 0x80000000, 201 }; 202 203 // 204 // Queries a boolean property of this message. 205 bool hasAttr(Attr attr) const; 206 // Adds attributes to the attribute set. 207 void addAttr(Attr attr); 208 209 // The specific operation 210 SendOp op = SendOp::INVALID; 211 212 // A bitset of the above attributes 213 Attr attributeSet = MessageInfo::Attr::NONE; 214 215 // Size (in bits) of one address 216 int addrSizeBits = 0; 217 // 218 // The size (in bits) of each element once stored in the register file. 219 int elemSizeBitsRegFile = 0; 220 // 221 // The size (in bits) of each element in memory. 222 // 223 // This can differ from elemSizeRegisterFile if there's any compression 224 // effects. For example, a byte gathering read will load one, two, 225 // four bytes into each 32b slot leaving the upper bits for the one- 226 // and two-byte case. 227 // 228 int elemSizeBitsMemory = 0; 229 // 230 // The number of vector elems or active channels in the cmask. 231 // This is the number of elements each address loads. 232 // 233 // For example a legacy untyped load with a channel mask of XYZ 234 // would be 3. Some scatter/gather messages have a SIMT vector 235 // component similar in function. 236 int elemsPerAddr = 0; 237 // 238 // For LOAD_QUAD and STORE_QUAD, this holds a bit mask of up to four 239 // bits with which channels are *enabled* (not disabled). 240 // 241 // The elemsPerAddr field will still be set 242 // (with the set cardinality here). 243 int channelsEnabled = 0; 244 // 245 // The number of channels in the size of the operation. 246 // (The "SIMD" size.) 247 int execWidth = 0; 248 249 // Caching options for the L1 cache (if supported) 250 CacheOpt cachingL1 = CacheOpt::INVALID; 251 // 252 // Caching options for the L3 cache (if supported) 253 // In some HDC messages this is bit 13. Some parts don't 254 // implement it though. 255 CacheOpt cachingL3 = CacheOpt::INVALID; 256 // 257 // The surface addressing model 258 AddrType addrType = AddrType::INVALID; 259 // 260 // The surface identifier (if applicable). E.g. BTI. 261 SendDesc surfaceId; 262 // 263 // possible immediate offset if the encoding supports it 264 int immediateOffset = 0; 265 // 266 // same as the above but only for block2d (mutally exclusive with above) 267 int immediateOffsetBlock2dX = 0, immediateOffsetBlock2dY = 0; 268 // 269 // A symbol value for this message (syntax). 270 // The syntax is not complete and IGA will not consume it directly 271 // (since some information isn't in necessarily in the descriptors). 272 std::string symbol; 273 // 274 // 275 // This may hold a useful string telling the user the exact message 276 // matching this specification up decode (if it exists). This is 277 // indended for for debugging only; the value and behavior are subject 278 // to change at any time. The nullptr is a possible value. 279 std::string description; 280 281 const char *docs = nullptr; 282 // 283 // A block message isBlockiga::MessageInfo284 bool isBlock() const { 285 return execWidth == 1 && (isLoad() || isStore()); 286 } 287 // isLoadiga::MessageInfo288 bool isLoad() const {return lookupSendOp(op).isLoad();} isStoreiga::MessageInfo289 bool isStore() const {return lookupSendOp(op).isStore();} isAtomiciga::MessageInfo290 bool isAtomic() const {return lookupSendOp(op).isAtomic();} 291 // 292 // An atomic that returns a value isAtomicLoadiga::MessageInfo293 bool isAtomicLoad() const {return hasAttr(Attr::ATOMIC_RETURNS);} 294 // 295 // A transpose data layout isTransposediga::MessageInfo296 bool isTransposed() const {return hasAttr(Attr::TRANSPOSED);} 297 298 // Enables the operation to be used within a predicate assignment. operator booliga::MessageInfo299 operator bool() const {return hasAttr(Attr::VALID);} 300 }; // class MessageInfo 301 operator |(MessageInfo::Attr a,MessageInfo::Attr b)302 static inline MessageInfo::Attr operator |( 303 MessageInfo::Attr a, MessageInfo::Attr b) 304 { 305 return MessageInfo::Attr(int(a) | int(b)); 306 } operator |=(MessageInfo::Attr & a,MessageInfo::Attr b)307 static inline MessageInfo::Attr &operator |=( 308 MessageInfo::Attr &a, MessageInfo::Attr b) 309 { 310 return (a = a | b); 311 } operator &(MessageInfo::Attr a,MessageInfo::Attr b)312 static inline bool operator &(MessageInfo::Attr a, MessageInfo::Attr b) { 313 return (int(a) & int(b)) != 0; 314 } hasAttr(Attr attr) const315 inline bool MessageInfo::hasAttr(Attr attr) const { 316 return attributeSet & attr; 317 } addAttr(Attr attr)318 inline void MessageInfo::addAttr(Attr attr) { 319 attributeSet = attributeSet | attr; 320 } 321 322 // for legacy encodings where the SFID comes from bits 323 SFID sfidFromEncoding(Platform p, uint32_t sfidBits); 324 325 // The payload lengths for a given message. 326 // Negative values indicate that the value is unknown or could be variable. 327 struct PayloadLengths { 328 int dstLen = -1; 329 int src0Len = -1, src1Len = -1; 330 bool uvrlod = false; 331 PayloadLengthsiga::PayloadLengths332 PayloadLengths() { } 333 334 // This attempts to deduce payload lengths from the given inputs. 335 PayloadLengths( 336 Platform p, 337 SFID sfid, 338 ExecSize execSize, 339 uint32_t desc); 340 341 // Same as above, but given a Op::SEND* 342 // 343 // For older platforms this will extract the SFID from exDesc 344 PayloadLengths( 345 Platform p, 346 ExecSize execSize, 347 uint32_t desc, 348 uint32_t exDesc); 349 }; 350 351 352 // Organizes various parts of syntax during decoding. This enables 353 // formatters to interleave real registers. 354 // 355 // LOAD: load, load_strided, load_cmask, fence 356 // MNEMONIC SFID CONTROLS 357 // $datareg DATATYPE 358 // SURFACE [ SCALE $addrreg IMMOFFSET ] ADDRTYPE 359 // ATOMIC: atomic_iinc 360 // MNEMONIC SFID CONTROLS 361 // $datareg DATATYPE 362 // SURFACE [ SCALE $addrreg IMMOFFSET ] ADDRTYPE 363 // $atomic-arg 364 // STORE: store, store_strided 365 // MNEMONIC SFID CONTROLS 366 // SURFACE [ SCALE $addrreg IMMOFFSET ] ADDRTYPE 367 // $datareg DATATYPE 368 // CONTROL: e.g. barrier 369 // MNEMONIC SFID CONTROLS 370 // SURFACE [ SCALE $addrreg IMMOFFSET ] ADDRTYPE 371 // $datareg DATATYPE 372 // 373 // Examples: 374 // load.ugm.ca.ca (32) r10:d32x4 bti<0x02>[r20-0x40]:a32 375 // load.ugm.ca.ca (1) r10:d32x4t flat[r20+0x40]:a64 376 // load.slm (1) r10:d32x4t flat[r20+0x40]:a64 377 // store_strided.ugm.wt.wb (16) bss<a0.4>[r20+0x40]:a32 r10:d32x4 378 // atomic_iinc.ugm.un.un (32) r10:d32 flat[r20-0x40]:a64 null 379 struct MessageSyntax { 380 enum class Layout { 381 // unset 382 INVALID = 0, 383 // e.g. load, load_strided, load_quad, load_blocks2d, ... 384 LOAD, 385 // e.g. store, store_quad, store_strided, ... 386 STORE, 387 // e.g. atomic_iinc, atomic_fadd 388 ATOMIC, 389 // e.g. barrier or eot 390 CONTROL 391 }; 392 Layout layout = Layout::INVALID; 393 isValidiga::MessageSyntax394 bool isValid() const {return layout != Layout::INVALID;} 395 // isLoadiga::MessageSyntax396 bool isLoad() const {return layout == Layout::LOAD;} isStoreiga::MessageSyntax397 bool isStore() const {return layout == Layout::STORE;} isAtomiciga::MessageSyntax398 bool isAtomic() const {return layout == Layout::ATOMIC;} isControliga::MessageSyntax399 bool isControl() const {return layout == Layout::CONTROL;} 400 401 std::string mnemonic; // e.g. "load" or "load_block" 402 // SFID sfid; // e.g. "ugm" 403 std::string controls; // e.g. ".ugm.d32.a64.ca.ca" 404 405 // address stuff 406 std::string surface; // e.g. "bti[0x2]", "bti[a0.4]", or "" (flat) 407 std::string scale; // e.g. 4*... 408 std::string immOffset; // e.g. -0x40 409 410 // emits rough syntax 411 std::string str( 412 std::string execInfo, 413 std::string dataReg, 414 std::string addrReg, 415 std::string atmoicArgReg) const; 416 417 // orders the operands in a symbolic form 418 // (suffixes surface, scaling and offset) 419 std::string sym() const; 420 }; // MessageSyntax 421 422 // 423 // Returns the resulting information of a message decode 424 struct DecodeResult { 425 MessageInfo info; 426 MessageSyntax syntax; 427 DiagnosticList warnings; 428 DiagnosticList errors; 429 DecodedDescFields fields; 430 operator booliga::DecodeResult431 operator bool() const {return errors.empty();} 432 }; 433 434 // Attempts to decode the descriptor for 435 DecodeResult tryDecode( 436 Platform p, SFID sfid, ExecSize execSize, 437 SendDesc exDesc, SendDesc desc, 438 DecodedDescFields *fields); 439 440 // 441 // returns true if the SFID on a given platform is eligible for symbolic 442 // translate for load/store syntax; this function enables us to 443 // incrementally enable load/store syntax 444 bool sendOpSupportsSyntax(Platform p, SendOp op, SFID sfid); 445 // 446 bool isLscSFID(Platform p, SFID sfid); 447 // 448 struct VectorMessageArgs { 449 SFID sfid = SFID::INVALID; 450 SendOp op = SendOp::INVALID; 451 int execSize = 0; 452 CacheOpt cachingL1 = CacheOpt::DEFAULT; 453 CacheOpt cachingL3 = CacheOpt::DEFAULT; 454 // 455 AddrType addrType = AddrType::FLAT; 456 SendDesc addrSurface = 0; // a0 or imm 457 int addrScale = 1; // must be 1x, V*D, 2*V*2, or 4*V*D 458 int addrSize = 0; 459 int addrOffset = 0; // imm only 460 int addrOffsetX = 0; // block2d only 461 int addrOffsetY = 0; // block2d only 462 int dataSizeReg = 0; 463 int dataSizeMem = 0; 464 bool dataSizeExpandHigh = 0; // d8u32h 465 union { 466 struct { 467 short dataVectorSize; 468 bool dataTranspose; 469 bool dataVnni; 470 }; 471 // 472 // used for LOAD_QUAD, STORE_QUAD, ... 473 // e.g. this might map to to dc1 untyped read/write ops 474 uint32_t dataComponentMask = 0; // x,y,z,w (x-enabled is bit 0, ...) 475 }; 476 477 /////////////////////////////////////////////////////////////////////// 478 // creates an initial empty message VectorMessageArgsiga::VectorMessageArgs479 constexpr VectorMessageArgs() { } 480 481 // returns the logical count of elements per address 482 // for simple vector messages, it's dataVectorSize, but for 483 // messages with a component mask, it's the number of enabled channels elementsPerAddressiga::VectorMessageArgs484 int elementsPerAddress() const { 485 if (lookupSendOp(op).hasChMask()) { 486 int n = 0; 487 for (int i = 0; i < 4; i++) 488 n += (((1 << i) & dataComponentMask) ? 1 : 0); 489 return n; 490 } else { 491 return dataVectorSize; 492 } 493 } 494 isLoadiga::VectorMessageArgs495 bool isLoad() const {return lookupSendOp(op).isLoad();} isStoreiga::VectorMessageArgs496 bool isStore() const {return lookupSendOp(op).isStore();} isAtomiciga::VectorMessageArgs497 bool isAtomic() const {return lookupSendOp(op).isAtomic();} hasCMaskiga::VectorMessageArgs498 bool hasCMask() const {return lookupSendOp(op).hasChMask();} 499 }; // VectorMessageArgs 500 501 bool encodeDescriptors( 502 Platform p, 503 const VectorMessageArgs &vma, 504 SendDesc &exDesc, 505 SendDesc &desc, 506 std::string &err); 507 } // iga:: 508 509 #endif 510