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 #include "MessageDecoder.hpp"
10 
11 using namespace iga;
12 
13 static const char *MDC_DS_MEANINGS[] {
14     "DE1 (1 data element per address)",
15     "DE2 (2 data elements per address)",
16     "DE4 (4 data elements per address)",
17     "DE8 (8 data elements per address)",
18 };
19 
20 
21 // https://gfxspecs.intel.com/Predator/Home/Index/44782
22 // https://gfxspecs.intel.com/Predator/Home/Index/44783
23 // https://gfxspecs.intel.com/Predator/Home/Index/44785
24 using HDCOpcode = uint32_t;
25 enum DC0 : uint32_t {
26     /////////////////////////////////////////
27     MSD0R_OWB      = 0x00, // oword block read (unaligned)
28     MSD0R_OWAB     = 0x01, // oword/hword block read (aligned)
29     MSD0W_OWB      = 0x08, // oword block write
30     MSD0W_HWAB     = 0x09, // hword block write (aligned)
31     MSD0R_OWDB     = 0x02, // dual block read
32     MSD0W_OWDB     = 0x0A, // dual block write
33     //
34     MSD0R_BS       = 0x04, // byte gathered read
35     MSD0W_BS       = 0x0C, // byte scattered write
36     //
37     MSD0R_DWS      = 0x03, // dword gathered read
38     MSD0W_DWS      = 0x0B, // dword scattered write
39     //
40     MSD0R_QWS      = 0x05, // qword gathered write
41     MSD0W_QWS      = 0x0D, // qword scattered write
42     //
43     MSD_MEMFENCE   = 0x07,
44     //
45 };
46 enum DC1 : uint32_t {
47     /////////////////////////////////////////
48     MSD1R_US       = 0x01, // untyped read
49     MSD1W_US       = 0x09, // untyped write
50     //
51     MSD1R_A64_US   = 0x11, // a64 untyped read
52     MSD1W_A64_US   = 0x19, // a64 untyped write
53     //
54     MSD1R_A64_BS   = 0x10, // byte gathered read
55     MSD1W_A64_BS   = 0x1A, // byte scattered write
56     MSD1R_A64_DWS  = (0x1 << 8) | MSD1R_A64_BS,
57     MSD1W_A64_DWS  = (0x1 << 8) | MSD1W_A64_BS,
58     MSD1R_A64_QWS  = (0x2 << 8) | MSD1R_A64_BS,
59     MSD1W_A64_QWS  = (0x2 << 8) | MSD1W_A64_BS,
60     MSD1RS_A64_BS  = (0x3 << 8) | MSD1R_A64_BS,
61     //
62     MSD1R_A64_HWB  = 0x14,
63     MSD1W_A64_HWB  = 0x15,
64     //
65     MSD1W_A64_DWAF = 0x1D,
66     MSD1W_DWAF     = 0x1B,
67     // MSD1W_A64_QWAI = (1 << 12) | 0x12,
68     // MSD1W_A64_DWAI = (0 << 12) | 0x12,
69     MSD1W_A64_AI   = 0x12,
70     //
71     MSD1W_DWAI     = 0x02,
72     //
73     MSD1R_MB       = 0x04,
74     MSD1W_MB       = 0x0A,
75     //
76     MSD1R_TS       = 0x05,
77     MSD1W_TS       = 0x0D,
78     MSD1RS_TS      = 0x0E,
79     //
80     MSD1A_DWAC     = 0x0B,
81     MSD1A_DWTAI    = 0x06,
82     //
83     // XE+
84     // e.g. MSD1R_WAC MSD1W_WAC => MSD1A_WAC (use "a" for atomic)
85     MSD1A_WAC      = 0x0C, // typed atomic 16b int counter
86     MSD1A_WTAI     = 0x07, // typed atomic 16b int op
87     MSD1A_A64_WAF  = 0x1E, // typed atomic 16b float
88     MSD1A_WAF      = 0x1C,
89     MSD1A_A64_WAI  = 0x13,
90     MSD1A_WAI      = 0x03,
91 };
92 
93 
94 struct MessageDecoderHDC : MessageDecoderLegacy {
MessageDecoderHDCMessageDecoderHDC95     MessageDecoderHDC(
96         Platform _platform, SFID _sfid, ExecSize execSize,
97         SendDesc _exDesc, SendDesc _desc,
98         DecodeResult &_result)
99         : MessageDecoderLegacy(
100             _platform, _sfid, execSize,
101             _exDesc, _desc, _result)
102     {
103     }
104 
ensurePlatformLTMessageDecoderHDC105     void ensurePlatformLT(Platform removed) {
106         if (platform() >= removed) {
107             error(14, 5, "operation not supported on this platform");
108         }
109     }
ensurePlatformLEMessageDecoderHDC110     void ensurePlatformLE(Platform removed) {
111         if (platform() > removed) {
112             error(14, 5, "operation not supported on this platform");
113         }
114     }
ensurePlatformGEMessageDecoderHDC115     void ensurePlatformGE(Platform introduced) {
116         if (platform() < introduced) {
117             error(14, 5, "operation not supported on this platform");
118         }
119     }
ensurePlatformInMessageDecoderHDC120     void ensurePlatformIn(Platform first, Platform last) {
121         if (platform() < first || platform() > last) {
122             error(14, 5, "operation not supported on this platform");
123         }
124     }
125 
126     ///////////////////////////////////////////////////////////////////////////
127     // decoder helpers
decodeXXX_HWMessageDecoderHDC128     int decodeXXX_HW(int off, int len, const char *fieldName) {
129         // scratch's use of DataElements:MDC_DB_HW uses 2 bits
130         // DataElements:MDC_DB_HW for A32 uses 3 bits (starting at bit 8)
131         // the A64 version is always [10:8]
132         auto bits = getDescBits(off,len);
133         // 0 -> 1 block, 1 -> 2 blocks, 2 -> 4 blocks, 3 -> 8 blocks
134         int val = (int)(1 << bits);
135         std::stringstream ss;
136         ss << val << " 256b blocks";
137         addField(fieldName, off, len, getDescBits(off,len), ss.str());
138         return val;
139     }
decodeMDC_A64_DB_HWMessageDecoderHDC140     int decodeMDC_A64_DB_HW(int off) {
141         return decodeXXX_HW(off, 3, "DataElements:MDC_A64_DB_HW");
142     }
decodeMDC_DB_HWMessageDecoderHDC143     int decodeMDC_DB_HW(int off, int len) {
144         return decodeXXX_HW(off, len, "DataElements:MDC_DB_HW");
145     }
146     //
decodeXXX_OWMessageDecoderHDC147     int decodeXXX_OW(int off, const char *fieldName) {
148         int bits = getDescBits(off,3);
149         int ows = 0;
150         const char *descs = "???";
151         // MDC_DB_OW and MDC_64_DB_OW
152         // 1L, 1H, 2, 4, 8, 16
153         switch (bits) {
154         case 0: ows = 1; descs = "1L (accesses low OWord of GRF)"; break;
155         case 1: ows = 1; descs = "1H (accesses second OWord of GRF)"; break;
156         case 2: ows = 2; descs = "2 OWords"; break;
157         case 3: ows = 4; descs = "4 OWords"; break;
158         case 4: ows = 8; descs = "8 OWords"; break;
159         case 5:
160             ensurePlatformGE(Platform::XE_HPG);
161             ows = 16; descs = "16 OWords";
162             break;
163         default: break;
164         }
165         addField(fieldName, off, 3, bits, descs);
166         return ows;
167     }
decodeMDC_A64_DB_OWMessageDecoderHDC168     int decodeMDC_A64_DB_OW(int off) {
169         return decodeXXX_OW(off, "DataElements:MDC_A64_DB_OW");
170     }
decodeMDC_DB_OWMessageDecoderHDC171     int decodeMDC_DB_OW(int off) {
172         return decodeXXX_OW(off, "DataElements:MDC_DB_OW");
173     }
174 
decodeMDC_DSMessageDecoderHDC175     int decodeMDC_DS(int off) {
176         auto bits = getDescBits(off,2);
177         addField("DataElements:MDC_DS", off, 2, bits, MDC_DS_MEANINGS[bits]);
178         return (1 << (int)bits);
179     }
MDC_A64_DSMessageDecoderHDC180     int MDC_A64_DS(int off) {
181         auto bits = getDescBits(off,2);
182         addField("DataElements:MDC_A64_DS", off, 2, bits, MDC_DS_MEANINGS[bits]);
183         return (1 << (int)bits);
184     }
decodeMDC_DWS_DSMessageDecoderHDC185     int decodeMDC_DWS_DS(int off) {
186         auto bits = getDescBits(off,2);
187         static const char *meanings[] {
188             "Fill low 1 byte per DW",
189             "Fill low 2 bytes per DW",
190             "Fill all 4 bytes per DW",
191             "???"
192         };
193         addField("DataElements:MDC_DWS_DS", off, 2, bits, meanings[bits]);
194         return (1 << (int)bits);
195     }
196 
decodeMDC_SM2XMessageDecoderHDC197     int decodeMDC_SM2X(int off, bool reversed) {
198 
199         int simd = 0;
200         if (reversed) {
201             int bits =
202                 decodeDescBitField("SimdMode:MDC_SM2R", off, "SIMD8", "SIMD16");
203             simd = bits ? 8 : 16;
204         } else {
205             int bits =
206                 decodeDescBitField("SimdMode:MDC_SM2R", off, "SIMD16", "SIMD8");
207             simd = bits ? 16 : 8;
208         }
209 
210         if (platform() >= Platform::XE_HPC) {
211             if (simd == 16) {
212                 error(off, 1, "invalid value for this platform");
213             }
214             simd *= 2;
215         }
216         return simd;
217     }
decodeMDC_SM2RMessageDecoderHDC218     int decodeMDC_SM2R(int off) {return decodeMDC_SM2X(off, true);}
decodeMDC_SM2SMessageDecoderHDC219     int decodeMDC_SM2S(int off) {return decodeMDC_SM2X(off, false);}
decodeMDC_SM3MessageDecoderHDC220     int decodeMDC_SM3(int off) {
221         auto bits = getDescBits(off, 2);
222         int simd = 0;
223         const char *simdStr = "?";
224         switch (bits) {
225         case 1: simd = 16; simdStr = "SIMD16"; break;
226         case 2: simd = 8;  simdStr = "SIMD8"; break;
227         default: error(off, 2, "invalid value"); break;
228         }
229         if (platform() >= Platform::XE_HPC) {
230             if (bits == 2) {
231                 // illegal on XeHPC+
232                 error(off, 1, "invalid value for this platform");
233             }
234         }
235         addField("SimdMode:MDC_SM3", off, 2, bits, simdStr);
236         return simd;
237     }
decodeMDC_CMASKMessageDecoderHDC238     int decodeMDC_CMASK() {
239         auto bits = getDescBits(8, 4);
240         std::stringstream ss;
241         int vecLen = 0;
242         if (bits == 0xF) {
243             error(8, 4, "channel mask must have one element not disabled");
244         }
245         for (int i = 0; i < 4; i++) {
246             if (((1 << i) & bits) == 0) {
247                 if (vecLen > 0)
248                     ss << ", ";
249                 ss << "XYZW"[i];
250                 vecLen++;
251             }
252         }
253         if (vecLen == 0)
254             ss << "no channels enabled";
255         else
256             ss << " enabled";
257         addField("ChannelDisableMask:MDC_CMASK", 8, 4, bits, ss.str());
258         return vecLen;
259     }
260 
261 
262 
263     // returns true if high slot group
decodeMDC_SG3MessageDecoderHDC264     bool decodeMDC_SG3() {
265         auto bits = getDescBits(12, 2);
266         const char *sym = "??";
267         switch (bits) {
268         case 0: sym = "SG4x2"; break;
269         case 1:
270             sym = "SG8L";
271             // in XeHPC this becomes the default
272             if (platform() >= Platform::XE_HPC)
273                 sym = "SIMD16";
274             break;
275         case 2: sym = "SG8U"; break;
276         default:
277             error(12,2,"invalid slot group value");
278         }
279         addField("SlotGroup:MDC_SG3", 12, 2, bits, sym);
280         return bits == 2;
281     }
282 
decodeMDC_SG2MessageDecoderHDC283     bool decodeMDC_SG2() {
284         auto bits = getDescBits(12,1);
285         const char *sym = "??";
286         switch (bits) {
287         case 0:
288             sym = "SG8L";
289             // in XeHPC this becomes the default
290             if (platform() >= Platform::XE_HPC)
291                 sym = "SIMD16";
292             break;
293         case 1: sym = "SG8U"; break;
294         default: break;
295         }
296         addField("SlotGroup:MDC_SG2", 12, 1, bits, sym);
297         return bits == 1;
298     }
299 
decodeMDC_IARMessageDecoderHDC300     CacheOpt decodeMDC_IAR() {
301         int bits = decodeDescBitField("MDC_IAR", 13, "disabled", "enabled");
302         return bits ? CacheOpt::READINVALIDATE : CacheOpt::DEFAULT;
303     }
304 
305     ///////////////////////////////////////////////////////////////////////////
306     //
307 
308     // allows different data sizes in mem and reg
setHdcMessageXMessageDecoderHDC309     void setHdcMessageX(
310         std::string msgSym,
311         std::string msgDesc,
312         SendOp op,
313         int addrSizeBits,
314         int bitsPerElemReg,
315         int bitsPerElemMem,
316         int elemsPerAddr,
317         int execSize,
318         MessageInfo::Attr extraAttrs)
319     {
320         CacheOpt caching = CacheOpt::DEFAULT;
321         const SendOpDefinition &opInfo = lookupSendOp(op);
322         std::stringstream ss;
323         ss << "hdc_";
324         ss << msgSym; // e.g. "load"
325         if (execSize == 8 || execSize == 16)
326             ss << "_simd" << execSize;
327 
328         if (instExecSize != ExecSize::INVALID) {
329             // e.g. a SIMD4 message will mask out the top bits
330             execSize = std::min(execSize, int(instExecSize));
331         }
332 
333         ss << ".";
334         int bti = 0;
335         if (!(extraAttrs & MessageInfo::Attr::SCRATCH)) {
336             bti = decodeBTI(addrSizeBits);
337         }
338         AddrType addrType = AddrType::BTI;
339         uint32_t surfaceId = 0;
340         if (addrSizeBits == 32) {
341             if (extraAttrs & MessageInfo::Attr::SCRATCH) {
342                 ss << "scratch";
343                 ss << "+" << 32*getDescBits(0, 12);
344             } else if (bti == SLM_BTI) {
345                 ss << "slm";
346                 addrType = AddrType::FLAT;
347                 surfaceId = 0;
348                 extraAttrs |= MessageInfo::Attr::SLM;
349             } else if (bti == COHERENT_BTI || bti == NONCOHERENT_BTI) {
350                 ss << "stateless";
351                 if (bti != COHERENT_BTI) {
352                     ss << "_incoherent";
353                     caching = CacheOpt::CACHED;
354                 } else {
355                     caching = CacheOpt::UNCACHED;
356                 }
357                 addrType = AddrType::FLAT;
358             } else {
359                 addrType = AddrType::BTI;
360                 surfaceId = bti;
361                 ss << "bti[" << bti << "]";
362             }
363         } else if (addrSizeBits == 64) {
364             ss << "stateless";
365             if (bti != COHERENT_BTI) {
366                 ss << "_incoherent";
367                 caching = CacheOpt::CACHED;
368             } else {
369                 caching = CacheOpt::UNCACHED;
370             }
371             addrType = AddrType::FLAT;
372             if (bti != COHERENT_BTI && bti != NONCOHERENT_BTI)
373                 error(0, 8, "must have 0xFF or 0xFD BTI");
374         }
375         ss << ".a" << addrSizeBits;
376         if (bitsPerElemReg == bitsPerElemMem) {
377             ss << ".d" << bitsPerElemReg;
378         } else {
379             ss << ".d" << bitsPerElemMem << "u" << bitsPerElemReg;
380         }
381         int chEnMask = 0;
382         if (opInfo.hasChMask()) {
383             ss << ".";
384             // in legacy HDC messages, this is a channel disable mask
385             auto chDisabled = getDescBits(8,4);
386             chEnMask = ~chDisabled & 0xF;
387             if ((chDisabled & 0x1) == 0) {
388                 ss << 'x';
389             }
390             if ((chDisabled & 0x2) == 0) {
391                 ss << 'y';
392             }
393             if ((chDisabled & 0x4) == 0) {
394                 ss << 'z';
395             }
396             if ((chDisabled & 0x8) == 0) {
397                 ss << 'w';
398             }
399         } else {
400             if (elemsPerAddr > 1 ||
401                 (extraAttrs & MessageInfo::Attr::TRANSPOSED))
402             {
403                 ss << "x" << elemsPerAddr;
404             }
405         }
406 
407         // if DC2, ExDesc[31:16] is immediate offset
408         if (sfid == SFID::DC2 && exDesc.isImm())
409             result.info.immediateOffset = exDesc.imm >> 16;
410         setScatterGatherOpX(
411             ss.str(),
412             msgDesc,
413             op,
414             addrType,
415             SendDesc(surfaceId),
416             caching,
417             caching,
418             addrSizeBits,
419             bitsPerElemReg, bitsPerElemMem,
420             elemsPerAddr,
421             execSize,
422             extraAttrs);
423         result.info.channelsEnabled = chEnMask;
424     }
425     // data size is same in mem and reg (typical case)
setHdcMessageMessageDecoderHDC426     void setHdcMessage(
427         std::string msgSym,
428         std::string msgDesc,
429         SendOp op,
430         int addrSize,
431         int bitsPerElem,
432         int elemsPerAddr,
433         int execSize,
434         MessageInfo::Attr extraAttrs)
435     {
436         setHdcMessageX(
437             msgSym,
438             msgDesc,
439             op,
440             addrSize,
441             bitsPerElem, bitsPerElem,
442             elemsPerAddr,
443             execSize,
444             extraAttrs);
445     }
446 
setHdcOwBlockMessageDecoderHDC447     void setHdcOwBlock(
448         std::string msgSym,
449         std::string msgDesc,
450         SendOp op,
451         int addrSize,
452         MessageInfo::Attr extraAttrs)
453     {
454         enum MDC_A64_DB_OW {
455             OW1L = 0x0,
456             OW1H = 0x1,
457             OW2  = 0x2,
458             OW4  = 0x3,
459             OW8  = 0x4,
460         };
461 
462         auto owBits = getDescBits(8, 3);
463         if (owBits == OW1H) {
464             extraAttrs |= MessageInfo::Attr::EXPAND_HIGH;
465         }
466         extraAttrs |= MessageInfo::Attr::TRANSPOSED;
467 
468         int elems = addrSize == 64 ?
469             decodeMDC_A64_DB_OW(8) :
470             decodeMDC_DB_OW(8);
471         std::stringstream ss;
472         ss << msgDesc << " x" << elems;
473         if (owBits == OW1H)
474             ss << "H";
475         msgDesc = ss.str();
476 
477         setHdcMessageX(
478             msgSym,
479             msgDesc,
480             op,
481             addrSize,
482             128, 128,
483             elems,
484             1, // SIMD
485             extraAttrs);
486     }
487 
setHdcHwBlockMessageDecoderHDC488     void setHdcHwBlock(
489         std::string msgSym,
490         std::string msgDesc,
491         SendOp op,
492         int addrSize,
493         int blockCountOffset,
494         int blockCountLen,
495         MessageInfo::Attr extraAttrs)
496     {
497         extraAttrs |= MessageInfo::Attr::TRANSPOSED;
498 
499         int elems =
500             addrSize == 64 ?
501             decodeMDC_A64_DB_HW(blockCountOffset) :
502             decodeMDC_DB_HW(blockCountOffset, blockCountLen);
503         std::stringstream ss;
504         ss << msgDesc << " x" << elems;
505         msgDesc = ss.str();
506 
507         setHdcMessageX(
508             msgSym,
509             msgDesc,
510             op,
511             addrSize,
512             256, 256,
513             elems,
514             1, // SIMD
515             extraAttrs);
516     }
517 
setHdcUntypedSurfaceMessageMessageDecoderHDC518     void setHdcUntypedSurfaceMessage(
519         std::string msgDesc,
520         bool isRead,
521         int addrSizeBits,
522         MessageInfo::Attr extraAttrs)
523     {
524         std::string msgSym = isRead ? "untyped_load" : "untyped_store";
525         extraAttrs |= MessageInfo::Attr::HAS_CHMASK;
526         //
527         appendCMask(msgDesc);
528         //
529         setHdcMessage(
530             msgSym,
531             msgDesc,
532             isRead ? SendOp::LOAD_QUAD : SendOp::STORE_QUAD,
533             addrSizeBits,
534             32,
535             decodeMDC_CMASK(),
536             decodeMDC_SM3(12),
537             extraAttrs);
538     }
539 
appendCMaskMessageDecoderHDC540     void appendCMask(std::string &msgDesc) {
541         auto cMaskBits = getDescBits(8, 4);
542         msgDesc += " with ";
543         for (int i = 0; i < 4; i++) {
544             if ((cMaskBits & (1 << i)) == 0) {
545                 // NOTE: legacy untyped message channel masks are a
546                 // disable bit
547                 msgDesc += "xyzw"[i];
548             }
549         }
550     }
551 
setHdcTypedSurfaceMessageMessageDecoderHDC552     void setHdcTypedSurfaceMessage(
553         bool isRead,
554         const char *doc,
555         const char *docXe,
556         bool returnsStatus = false)
557     {
558         std::string msgDesc = isRead ?
559             "typed surface read" : "typed surface write";
560         addField("MessageType", 14, 5, getDescBits(14, 5), msgDesc);
561 
562         std::string msgSym = isRead ? "typed_load" : "typed_store";
563         if (decodeMDC_SG3()) {
564             msgDesc += " (high slot group)";
565             msgSym += "_sgh";
566         }
567         if (returnsStatus) {
568             msgDesc += " returning status";
569             msgSym += "_wstatus";
570         }
571         //
572         appendCMask(msgDesc);
573         //
574         setHdcMessage(
575             msgSym,
576             msgDesc,
577             isRead ? SendOp::LOAD_QUAD : SendOp::STORE_QUAD,
578             32, // addrSize
579             32, // dataSize
580             decodeMDC_CMASK(),
581             DEFAULT_EXEC_SIZE / 2, // HDC typed is always SIMD8
582             MessageInfo::Attr::HAS_CHMASK | MessageInfo::Attr::HAS_UVRLOD);
583         setDoc(doc, docXe, nullptr);
584     }
585 
setHdcFloatAtomicMessageMessageDecoderHDC586     void setHdcFloatAtomicMessage(
587         const char *msgNameDesc, int addrSize, int dataSize,
588         const char *docNoRet, const char *docWiRet,
589         const char *docNoRetXe, const char *docWiRetXe)
590     {
591         addField("MessageType", 14, 5, getDescBits(14, 5), msgNameDesc);
592 
593         std::string msgSym = "atomic_float?";
594         std::string msgDesc;
595         SendOp op = SendOp::INVALID;
596         auto atBits = getDescBits(8, 3);
597         switch (atBits) {
598         case 0x1:
599             op = SendOp::ATOMIC_FMAX;
600             msgSym ="atomic_fmax";
601             msgDesc = "max";
602             break;
603         case 0x2:
604             op = SendOp::ATOMIC_FMIN;
605             msgSym ="atomic_fmin";
606             msgDesc = "min";
607             break;
608         case 0x3: op = SendOp::ATOMIC_FCAS;
609             msgSym ="atomic_fcas";
610             msgDesc = "fp-compare and swap ";
611             break;
612             // XeHP+
613         case 0x4:
614             op = SendOp::ATOMIC_FADD;
615             msgSym ="atomic_fadd";
616             msgDesc = "add";
617             break;
618         case 0x5:
619             op = SendOp::ATOMIC_FSUB;
620             msgSym ="atomic_fsub";
621             msgDesc = "subtract";
622             break;
623             // they just wedged in 64b as part of the 32b float atomic message
624         case 0x6:
625             op = SendOp::ATOMIC_FADD;
626             msgSym ="atomic_fadd";
627             msgDesc = "64b add";
628             dataSize = 64;
629             break;
630         case 0x7:
631             op = SendOp::ATOMIC_FSUB;
632             msgSym ="atomic_fsub";
633             msgDesc = "64b subtract";
634             dataSize = 64;
635             break;
636         default:
637             error(8, 3, " (unknown float op)"); // fallthrough
638         }
639         std::stringstream ssDesc;
640         ssDesc << msgNameDesc << " " << msgDesc << " (" << dataSize << "b)";
641         addField("AtomicOp:MDC_AOP", 8, 3, atBits, ssDesc.str());
642 
643         MessageInfo::Attr extraAttrs = MessageInfo::Attr::NONE;
644         if (decodeDescBitField(
645             "ReturnDataControl", 13, "no return value", "returns new value"))
646         {
647             extraAttrs |= MessageInfo::Attr::ATOMIC_RETURNS;
648             msgSym += "_ret";
649             ssDesc << " with return";
650             setDoc(docWiRet, docWiRetXe, nullptr);
651         }
652         else
653         {
654             setDoc(docNoRet, docNoRetXe, nullptr);
655         }
656         if (op != SendOp::INVALID) {
657             setHdcMessage(
658                 msgSym,
659                 ssDesc.str(),
660                 op,
661                 addrSize,
662                 dataSize,
663                 1,
664                 addrSize == 64 ? decodeMDC_SM2S(12) : decodeMDC_SM2R(12),
665                 extraAttrs);
666         }
667     } // setHdcFloatAtomicMessage
668 
setHdcIntAtomicMessageMessageDecoderHDC669     void setHdcIntAtomicMessage(
670         const char *typedUntyped, // "typed" or "untyped"
671         const char *msgDesc0,
672         int addrSize,
673         int dataSize,
674         int simdSize,
675         const char *docNoRet, const char *docWiRet,
676         const char *docNoRet12, const char *docWiRet12)
677     {
678         std::stringstream msgSym;
679         msgSym << typedUntyped << "_";
680         std::stringstream msgDesc;
681         msgDesc << typedUntyped << " " << msgDesc0;
682 
683         addField("MessageType", 14, 5, getDescBits(14, 5), msgDesc.str());
684 
685         std::string mOpName;
686         SendOp op = SendOp::INVALID;
687         auto aopBits = getDescBits(8, 4);
688         std::string opDesc;
689         switch (aopBits) {
690             // again with case 0x0 they wedged in a 64b CAS as part of the
691             // 32b message (note there's also a QW atomic message)
692         case 0x0: op =
693             SendOp::ATOMIC_ICAS;
694             mOpName = "atomic_icas";
695             opDesc = "64b integer compare and swap";
696             dataSize = 64;
697             break;
698             // The rest are 32b (or 16b)
699         case 0x1:
700             op = SendOp::ATOMIC_AND;
701             mOpName = "atomic_and";
702             opDesc = "logical AND";
703             break;
704         case 0x2:
705             op = SendOp::ATOMIC_OR;
706             mOpName = "atomic_or";
707             opDesc = "logical OR";
708             break;
709         case 0x3:
710             op = SendOp::ATOMIC_XOR;
711             mOpName = "atomic_xor";
712             opDesc = "logical XOR";
713             break;
714         case 0x4:
715             op = SendOp::ATOMIC_STORE;
716             mOpName = "atomic_store";
717             opDesc = "store";
718             break;
719         case 0x5:
720             op = SendOp::ATOMIC_IINC;
721             mOpName = "atomic_iinc";
722             opDesc = "integer increment";
723             break;
724         case 0x6:
725             op = SendOp::ATOMIC_IDEC;
726             mOpName = "atomic_idec";
727             opDesc = "integer decrement";
728             break;
729         case 0xF:
730             op = SendOp::ATOMIC_IPDEC;
731             mOpName = "atomic_iipdec";
732             opDesc = "integer pre-decrement (returns pre-decrement value)";
733             break;
734         case 0x7:
735             op = SendOp::ATOMIC_IADD;
736             mOpName = "atomic_iadd";
737             opDesc = "integer add";
738             break;
739         case 0x8:
740             op = SendOp::ATOMIC_ISUB;
741             mOpName = "atomic_isub";
742             opDesc = "integer subtract";
743             break;
744         case 0x9:
745             op = SendOp::ATOMIC_IRSUB;
746             mOpName = "atomic_irsub";
747             opDesc = "commuted integer subtract";
748             break;
749         case 0xA:
750             op = SendOp::ATOMIC_SMAX;
751             mOpName = "atomic_smax";
752             opDesc = "signed-integer max";
753             break;
754         case 0xB:
755             op = SendOp::ATOMIC_SMIN;
756             mOpName = "atomic_smin";
757             opDesc = "signed-integer min";
758             break;
759         case 0xC:
760             op = SendOp::ATOMIC_UMAX;
761             mOpName = "atomic_umax";
762             opDesc = "unsigned-integer max";
763             break;
764         case 0xD:
765             op = SendOp::ATOMIC_UMIN;
766             mOpName = "atomic_umin";
767             opDesc = "unsigned-integer min";
768             break;
769         case 0xE:
770             op = SendOp::ATOMIC_ICAS;
771             mOpName = "atomic_icas";
772             opDesc = "integer compare and swap";
773             break;
774             //
775         default:
776         {
777             std::stringstream ss;
778             ss << "0x" << std::uppercase << std::hex <<
779                 getDescBits(8,4) << "?";
780             mOpName = ss.str();
781             opDesc = mOpName;
782             error(8, 4, " unknown int atomic op");
783         }
784         }
785         msgSym << mOpName;
786         //
787         addField("AtomicIntegerOp", 8, 4, aopBits, opDesc);
788         //
789         MessageInfo::Attr extraAttrs = MessageInfo::Attr::NONE;
790         if (decodeDescBitField(
791             "ReturnDataControl", 13, "no return value", "returns new value"))
792         {
793             extraAttrs |= MessageInfo::Attr::ATOMIC_RETURNS;
794             msgSym << "_ret";
795             setDoc(docWiRet, docWiRet12, nullptr);
796         } else {
797             setDoc(docNoRet, docNoRet12, nullptr);
798         }
799         if (op != SendOp::INVALID) {
800             msgDesc << " " << opDesc;
801             setHdcMessage(
802                 msgSym.str(),
803                 msgDesc.str(),
804                 op,
805                 addrSize,
806                 dataSize,
807                 1,
808                 simdSize,
809                 extraAttrs);
810         }
811     } // setHdcIntAtomicMessage
812 
813     ///////////////////////////////////////////////////////////////////////////
tryDecodeMessageDecoderHDC814     void tryDecode() {
815         switch (sfid) {
816         case SFID::DCRO: tryDecodeDCRO(); break;
817         case SFID::DC0:  tryDecodeDC0();  break;
818         case SFID::DC1:  tryDecodeDC1();  break;
819             //////////////////////////////////////////////////////////////
820             // DC2 shouldn't be used after SKL
821         case SFID::DC2: error(0, 32, "unsupported DC2 op"); break;
822         default:
823             error(0, 0, "unsupported sfid");
824             return;
825         }
826     }
827 
828     void tryDecodeDCRO();
829     void tryDecodeDC0();
830     void tryDecodeDC0BSRW(bool isRead);
831     void tryDecodeDC0AlignedBlock();
832     void tryDecodeDC0Memfence();
833     void tryDecodeDC0ScratchBlock();
834     void tryDecodeDC1();
835 }; // MessageDecoderHDC
836 
837 
838 // Enum of all DCRO ops
839 // https://gfxspecs.intel.com/Predator/Home/Index/44785
840 enum DCRO_MT {
841     MT_CC_OWB  = 0x00,
842     MT_CC_OWAB = 0x01,
843     MT_CC_DWS  = 0x03,
844     // these are XeHP only
845     MT_US_CCS_OP     = 0x08, // cannot find BXML page
846     MT_A64_US_CCS_OP = 0x18,
847     MT_A64_US_UCW    = 0x19,
848     // XeHPG+
849     MT_TS_UCW        = 0x0D,
850     MT_TS_CCS_OP     = 0x0C,
851     MT_US_UCW        = 0x09,
852     MT_A64_CCS_PG_OP = 0x17,
853 };
854 
tryDecodeDCRO()855 void MessageDecoderHDC::tryDecodeDCRO() {
856     const int msgType = getDescBits(14, 5);
857     const char *desc = "???";
858 
859     auto setMessageTypeDesc = [&](const char *d) {
860         desc = d;
861         addField("MessageType", 14, 5, msgType, d);
862     };
863     switch (msgType) {
864     case MT_CC_OWB:  // constant           oword block read
865     case MT_CC_OWAB: // constant unaligned oword block read
866         setMessageTypeDesc(
867             msgType == MT_CC_OWB ?
868             "constant "      "oword block read" :
869             "constant aligned oword block read");
870         setHdcOwBlock(
871             msgType == MT_CC_OWB ?
872                 "const_load_block" :
873                 "aligned_const_load_block",
874             desc,
875             SendOp::LOAD,
876             32, // 32b address
877             MessageInfo::Attr::NONE);
878         result.info.cachingL3 = decodeMDC_IAR();
879         decodeMDC_HR();
880         setDoc(
881             msgType == MT_CC_OWB ? "7041" : "7043",
882             msgType == MT_CC_OWB ? "44767" : "44766",
883             nullptr);
884         break;
885     case MT_CC_DWS:
886         setMessageTypeDesc("constant dword gathering read");
887         result.info.cachingL3 = decodeMDC_IAR();
888         setHdcMessage(
889             "const_load",
890             "constant dword gathering read",
891             SendOp::LOAD,
892             32,
893             32,
894             decodeMDC_DWS_DS(10),
895             decodeMDC_SM2(8),
896             MessageInfo::Attr::NONE);
897         decodeExpected(9, 1, "LegacySimdMode", 1);
898         decodeMDC_H();
899         setDoc("7084", "44765", nullptr);
900         break;
901     // case MT_US_CCS_OP: // TODO: find BXML page
902     case MT_A64_US_CCS_OP:
903     {
904         setMessageTypeDesc("A64 untyped surface CCS operation");
905         decodeMDC_HF();
906         auto ccsOp = decodeDescField("SectorUpdateOpcode", 8, 4,
907             [] (std::stringstream &ss, uint32_t val){
908                 switch (val) {
909                 case 0x1: ss << "Slow Clear"; break;
910                 case 0x3: ss << "Slow Uncompress"; break;
911                 default: ss << "?";
912                 }
913             });
914         setHdcMessage(
915             "a64_untyped_ccs_op",
916             desc,
917             ccsOp == 0x1 ? SendOp::CCS_SC :  SendOp::CCS_SU,
918             64, // addr size
919             0, // data
920             1, // vec elems
921             decodeMDC_SM3(12),
922             MessageInfo::Attr::NONE);
923         setDoc("44763");
924         ensurePlatformGE(Platform::XE_HP);
925         break;
926     }
927     case MT_A64_US_UCW:
928         setMessageTypeDesc("A64 untyped surface uncompressed write");
929         setHdcMessage(
930             "a64_untyped_uncompressed_store_quad",
931             desc,
932             SendOp::STORE_UNCOMPRESSED_QUAD,
933             64, // addr size
934             32, // data size
935             decodeMDC_CMASK(),
936             decodeMDC_SM3(12),
937             MessageInfo::Attr::NONE);
938         decodeMDC_HF();
939         setDoc("44764");
940         ensurePlatformGE(Platform::XE_HP);
941         break;
942     case MT_A64_CCS_PG_OP:
943     {
944         setMessageTypeDesc("A64 page CCS update operation");
945         auto ccsOp = decodeDescField("PageUpdateOpcode", 8, 2,
946             [] (std::stringstream &ss, uint32_t val){
947                 switch (val) {
948                 case 0: ss << "Fast Clear"; break;
949                 case 2: ss << "Fast Uncompress"; break;
950                 default: ss << "?";
951                 }
952             });
953         int surfId = decodeBTI(64);
954         setSpecialOpX(
955             "a64_ccs_update",
956             desc,
957             ccsOp == 0x0 ? SendOp::CCS_PC : SendOp::CCS_PU,
958             AddrType::BTI,
959             SendDesc(surfId),
960             1,
961             0,
962             MessageInfo::Attr::NONE);
963         decodeMDC_HR();
964         setDoc("44762");
965         ensurePlatformGE(Platform::XE_HPG);
966         break;
967     }
968     case MT_TS_UCW:
969         setMessageTypeDesc("typed surface uncompressed write");
970         setHdcMessage(
971             "typed_uncompressed_store_quad",
972             desc,
973             SendOp::STORE_UNCOMPRESSED_QUAD,
974             32, // addr size
975             32, // data size
976             decodeMDC_CMASK(),
977             decodeMDC_SG3(),
978             MessageInfo::Attr::NONE);
979         decodeMDC_H();
980         setDoc("44773");
981         ensurePlatformGE(Platform::XE_HPG);
982         break;
983     case MT_TS_CCS_OP:
984     {
985         setMessageTypeDesc("typed surface CCS update message");
986         auto ccsOp = decodeDescField("SectorUpdateOpcode", 8, 4,
987             [] (std::stringstream &ss, uint32_t val){
988                 switch (val) {
989                 case 1: ss << "Slow Clear"; break;
990                 case 3: ss << "Slow Uncompress"; break;
991                 default: ss << "?";
992                 }
993             });
994         setHdcMessage(
995             "a64_typed_ccs_op",
996             desc,
997             ccsOp == 0x1 ? SendOp::CCS_SC :  SendOp::CCS_SU,
998             32, // addr size
999             32, // data
1000             1, // vec elems
1001             decodeMDC_SG3(),
1002             MessageInfo::Attr::NONE);
1003         decodeMDC_H();
1004         setDoc("44763");
1005         break;
1006     }
1007     case MT_US_UCW:
1008         setMessageTypeDesc("untyped surface uncompressed write");
1009         setHdcMessage(
1010             "untyped_uncompressed_store_quad",
1011             desc,
1012             SendOp::STORE_UNCOMPRESSED_QUAD,
1013             32, // addr size
1014             32, // data size
1015             decodeMDC_CMASK(),
1016             decodeMDC_SM3(12),
1017             MessageInfo::Attr::NONE);
1018         decodeMDC_H();
1019         setDoc("44775");
1020         ensurePlatformGE(Platform::XE_HPG);
1021         break;
1022     default:
1023         setMessageTypeDesc("unknown DCRO message");
1024         decodeMDC_H();
1025         (void)decodeBTI(32);
1026         error(14, 5, "unsupported DCRO op");
1027         return;
1028     }
1029 }
1030 
1031 // XE: DC0 https://gfxspecs.intel.com/Predator/Home/Index/44782
tryDecodeDC0()1032 void MessageDecoderHDC::tryDecodeDC0()
1033 {
1034     const int msgType = getDescBits(14, 5);
1035     const char *desc = "???";
1036     auto addMessageType = [&](const char *d) {
1037         addField("MessageType", 14, 5, msgType, d);
1038         desc = d;
1039     };
1040     switch (msgType) {
1041     case MSD0R_OWB: // oword block read (unaligned)
1042         addMessageType("oword block read");
1043         setHdcOwBlock(
1044             "load_block",
1045             desc,
1046             SendOp::LOAD,
1047             32, // all 32b addresses
1048             MessageInfo::Attr::NONE);
1049         setDoc("7028", "44722", nullptr);
1050         decodeMDC_HR();
1051         break;
1052     case MSD0R_OWAB: // aligned hword/oword block read
1053         tryDecodeDC0AlignedBlock();
1054         break;
1055     case MSD0W_OWB: // hword/oword block write
1056         addMessageType("oword block write");
1057         setHdcOwBlock(
1058             "store_block",
1059             desc,
1060             SendOp::STORE,
1061             32, // all 32b addresses
1062             MessageInfo::Attr::NONE);
1063         setDoc("7032", "44730", nullptr);
1064         decodeMDC_HR();
1065         break;
1066     case MSD0W_HWAB: // hword aligned block write
1067         addMessageType("hword aligned block write");
1068         setHdcOwBlock(
1069             "aligned_store_block",
1070             desc,
1071             SendOp::STORE,
1072             32, // all 32b addresses
1073             MessageInfo::Attr::NONE);
1074         setDoc("20862", "44727", nullptr);
1075         decodeMDC_HR();
1076         break;
1077         //
1078     case MSD0R_OWDB: // oword dual block read
1079         addMessageType("oword dual block read");
1080         setDoc("7029", nullptr, nullptr);
1081         result.info.description = desc;
1082         decodeMDC_HR();
1083         error(14, 5, "oword dual block read decode not supported");
1084         return;
1085     case MSD0W_OWDB: // oword dual block write
1086         addMessageType("oword dual block write");
1087         result.info.description = desc;
1088         setDoc("7033", nullptr, nullptr);
1089         decodeMDC_HR();
1090         error(14, 5, "oword dual block write decode not supported");
1091         return;
1092         //
1093     case MSD0R_BS: // byte gathered read
1094     case MSD0W_BS: // byte scattered write
1095         tryDecodeDC0BSRW(msgType == MSD0R_BS);
1096         break;
1097     //
1098     case MSD0R_DWS: // dword gathered read
1099     case MSD0W_DWS: // dword scattered write
1100     {
1101         bool isRead = msgType == MSD0R_DWS;
1102         const char *msgName = isRead ?
1103             "dword gathering read" : "dword scattering write";
1104         addMessageType(msgName);
1105         //
1106         int elemsPerAddr = decodeMDC_DWS_DS(10);
1107         std::stringstream ss;
1108         ss << msgName;
1109         if (elemsPerAddr != 1)
1110             ss << " x" << elemsPerAddr;
1111         //
1112         setHdcMessage(
1113             isRead ? "load" : "store",
1114             ss.str(),
1115             isRead ? SendOp::LOAD : SendOp::STORE,
1116             32,
1117             32,
1118             elemsPerAddr,
1119             decodeMDC_SM2(8),
1120             MessageInfo::Attr::NONE);
1121         result.info.cachingL3 = decodeMDC_IAR();
1122         setDoc(
1123             isRead ? "7067" : "7069",
1124             isRead ? "44718" : "44726",
1125             nullptr);
1126         decodeExpected(9, 1, "LegacySimdMode", 1);
1127         decodeMDC_H();
1128         break;
1129     }
1130     case MSD0R_QWS: // qword gather
1131     case MSD0W_QWS: // qword scatter
1132     {
1133         auto isRead = MSD0R_QWS;
1134         const char *msgName = isRead ?
1135             "qword gathering read" : "qword scattering write";
1136         addMessageType(msgName);
1137         //
1138         setHdcMessage(
1139             isRead ? "load" : "store",
1140             msgName,
1141             isRead ? SendOp::LOAD : SendOp::STORE,
1142             32, // addrs
1143             64, // data
1144             decodeMDC_DWS_DS(10),
1145             decodeMDC_SM2(8),
1146             MessageInfo::Attr::NONE);
1147         setDoc(
1148             isRead ? "33652" : "33653",
1149             isRead ? "44723" : "44731",
1150             nullptr);
1151         decodeExpected(9, 1, "LegacySimdMode", 1);
1152         decodeMDC_H();
1153         break;
1154     }
1155     case MSD_MEMFENCE:
1156         tryDecodeDC0Memfence();
1157         break;
1158     default:
1159         if (getDescBit(18) == 1) {
1160             tryDecodeDC0ScratchBlock();
1161         } else {
1162             addField("MessageType", 14, 5, msgType, "???");
1163             error(14, 5, "unsupported dc0 op");
1164             return;
1165         }
1166     } // end switch legacy DC0
1167 }
1168 
tryDecodeDC0BSRW(bool isRead)1169 void MessageDecoderHDC::tryDecodeDC0BSRW(bool isRead)
1170 {
1171     const uint32_t msgType = getDescBits(14, 5);
1172     const char *msgName = isRead ?
1173         "byte gathering read" : "byte scattering write";
1174 
1175     addField("MessageType", 14, 5, msgType, msgName);
1176 
1177     std::stringstream descs;
1178     descs << msgName;
1179     int memBytes = decodeMDC_DS(10);
1180     if (memBytes == 1)
1181         descs << " 8b";
1182     else if (memBytes == 2)
1183         descs << " 16b";
1184     else if (memBytes == 4)
1185         descs << " 32b";
1186 
1187     //
1188     // "byte" scattered always consumes a DW of GRF per channel,
1189     // but DWS_DS controls how many bytes are loaded per address
1190     // that might be 1, 2, 4 all packed into one DW.
1191     // So think of:
1192     //     DWS_DS == 0 (byte) as u8 aligned to u32 (upper bits undefined)
1193     //     DWS_DS == 1 (word) as u16 aligned to u32 (upper bits undefined)
1194     //     DWS_DS == 2 (dword) as u32
1195     setHdcMessageX(
1196         isRead ? "load" : "store",
1197         descs.str(),
1198         isRead ? SendOp::LOAD : SendOp::STORE,
1199         32, // 32b addrs
1200         32, // each channel occupies a DW in the reg file
1201         8*memBytes, // in memory it can be 1, 2, or 4 bytes
1202         1, // vector size always 1
1203         decodeMDC_SM2(8),
1204         MessageInfo::Attr::NONE);
1205     result.info.cachingL3 = decodeMDC_IAR();
1206     setDoc(isRead ? "7066" : "7068", isRead ? "44717" : "44725", nullptr);
1207     decodeMDC_H();
1208 }
1209 
tryDecodeDC0AlignedBlock()1210 void MessageDecoderHDC::tryDecodeDC0AlignedBlock()
1211 {
1212     const int msgType = getDescBits(14, 5);
1213     const char *descs ="aligned block read";
1214     const char *doc = "7030";
1215     bool isHw = false;
1216     if (platform() >= Platform::XE_HPG) {
1217         isHw = getDescBit(13);
1218         addField("BlockMessageSubtype", 13, 1, isHw, isHw ? "HWord" : "OWord");
1219         if (isHw) {
1220             descs ="aligned block read";
1221             doc = "44719";
1222         } else {
1223             doc = "44721";
1224         }
1225     } // else: [13] is reserved
1226     addField("MessageType", 14, 5, msgType, descs);
1227     if (isHw) {
1228         setHdcHwBlock(
1229             "aligned_load_block256",
1230             "hword aligned block read",
1231             SendOp::LOAD,
1232             32, // all 32b addresses
1233             8, 3, // [10:8]
1234             MessageInfo::Attr::NONE);
1235     } else {
1236         setHdcOwBlock(
1237             "aligned_load_block128",
1238             "oword aligned block read",
1239             SendOp::LOAD,
1240             32, // all 32b addresses
1241             MessageInfo::Attr::NONE);
1242     }
1243     setDoc(doc);
1244     decodeMDC_HR();
1245 }
1246 
tryDecodeDC0Memfence()1247 void MessageDecoderHDC::tryDecodeDC0Memfence()
1248 {
1249     const int msgType = getDescBits(14, 5);
1250     // memory fence
1251     addField("MessageType", 14, 5, msgType, "fence");
1252     //
1253     std::stringstream sym, descs;
1254     uint32_t surfId = getDescBits(0, 8);
1255     MessageInfo::Attr extraAttrs = MessageInfo::Attr::NONE;
1256     if (decodeDescBitField("Commit", 13,
1257         "off (return immediately)",
1258         "on (wait for fence commit)"))
1259     {
1260         sym << "sync_";
1261         descs << "synchronized ";
1262     }
1263     if (surfId == SLM_BTI) {
1264         (void)decodeBTI(32); // add the field
1265         sym << "slm_fence";
1266         descs << "SLM fence";
1267         extraAttrs |= MessageInfo::Attr::SLM;
1268     } else if (surfId == 0) {
1269         sym << "global_fence";
1270         descs << "global fence";
1271         if (getDescBits(9, 4) && getDescBit(8)) {
1272             error(8, 1, "L3 implies L1 flush");
1273         }
1274         descs << " flushing";
1275         if (decodeDescBitField("L1Flush", 8, "Flush L3", "FLush L1") != 0) {
1276             sym << ".l1";
1277             descs << " L1";
1278         }
1279         if (decodeDescField("L3 Flush Targets", 9, 4)) {
1280             if (getDescBits(9, 4) == 0xF) {
1281                 descs << " all L3 data";
1282                 sym << ".dcti";// data, const?, text, inst
1283             } else {
1284                 int n = 0;
1285                 descs << " L3";
1286                 sym << ".";
1287                 if (getDescBit(12)) {
1288                     sym << "d";
1289                     descs << " r/w data";
1290                 }
1291                 if (getDescBit(11)) {
1292                     if (n++ > 0)
1293                         descs << ",";
1294                     sym << "c";
1295                     descs << " constant data";
1296                 }
1297                 if (getDescBit(10)) {
1298                     if (n++ > 0)
1299                         descs << ",";
1300                     sym << "t";
1301                     descs << " texture data";
1302                 }
1303                 if (getDescBit(9)) {
1304                     if (n++ > 0)
1305                         descs << ",";
1306                     sym << "i";
1307                     descs << " instruction data";
1308                 }
1309             }
1310         }
1311     } else {
1312         error(0, 8, "invalid BTI for fence (must be 0x0 or 0xFE)");
1313     }
1314     setSpecialOpX(
1315         sym.str(),
1316         descs.str(),
1317         SendOp::FENCE,
1318         AddrType::FLAT,
1319         SendDesc(surfId),
1320         1,
1321         1,
1322         extraAttrs);
1323     setDoc("7049", "44768", nullptr);
1324     decodeMDC_HR();
1325 }
1326 
tryDecodeDC0ScratchBlock()1327 void MessageDecoderHDC::tryDecodeDC0ScratchBlock()
1328 {
1329     const int msgType = getDescBits(14, 5);
1330     // scratch read
1331     // scratch write
1332     //
1333     // scratch block is a muddy situation
1334     // they used to have ChannelMode at 16, so we want to ignore that
1335     // and only use bits
1336     bool isRead = getDescBit(17) == 0;
1337     const char *msgName = isRead ?
1338         "hword scratch block read" :  "hword scratch block write";
1339     addField("MessageType", 14, 5, msgType, msgName);
1340     //
1341     setHdcHwBlock(
1342         isRead ? "load_block" : "store_block",
1343         msgName,
1344         isRead ? SendOp::LOAD : SendOp::STORE,
1345         32, // r0.5
1346         12, 2, // [13:12] num HWs
1347         MessageInfo::Attr::SCRATCH);
1348     // scratch offset [11:0] (reg aligned)
1349     uint32_t hwOff = 32*
1350         decodeDescField("HWordOffset", 0, 12,
1351             [&] (std::stringstream &ss, uint32_t val) {
1352                 ss << val << " HWords from scratch base";
1353             });
1354     result.info.immediateOffset = hwOff;
1355     if (platform() < Platform::GEN10) {
1356         decodeDescBitField("ChannelMode", 16, "OWord", "DWord");
1357     }
1358     setDoc(isRead ? "7027" : "7031", isRead ? "44724" : "44732", nullptr);
1359 
1360     decodeMDC_HR();
1361 }
1362 
1363 #if 0
1364 // experimental work in a table-based approach
1365 
1366 struct Doc {
1367     Platform platform;
1368     const char *doc;
1369 
1370     constexpr Doc() : Doc(Platform::INVALID, nullptr) { }
1371     constexpr Doc(const char *d) : Doc(Platform::GEN6, d) { }
1372     constexpr Doc(Platform p, const char *d) : platform(p), doc(d) { }
1373 
1374     constexpr Doc(Doc &) = default;
1375     constexpr Doc(Doc &&) = default;
1376     constexpr Doc &operator=(const Doc &) = default;
1377 };
1378 static constexpr Doc INVALID_DOC;
1379 
1380 struct AddrSize {
1381     enum class Ord {ORD_A16 = 1, ORD_A32, ORD_A64} ordinal;
1382     constexpr AddrSize(Ord o) : ordinal(o) { }
1383     constexpr int bits() const {return 8 << unsigned(ordinal);}
1384     // std::string symbol() {}
1385     // static AddrSize FromSyntax(std::string);
1386 };
1387 constexpr AddrSize A16(AddrSize::Ord::ORD_A16);
1388 constexpr AddrSize A32(AddrSize::Ord::ORD_A32);
1389 constexpr AddrSize A64(AddrSize::Ord::ORD_A64);
1390 
1391 struct DataSize {
1392     int bitsInReg;
1393     int bitsInMem;
1394     // enum class ExtendFunction{NOP, ZEXT, SEXT} extend;
1395 
1396     constexpr DataSize(int bRf, int bM) : bitsInReg(bRf), bitsInMem(bM) { }
1397     constexpr DataSize(int b) : DataSize(b, b) { }
1398     constexpr int bitsInRegisterFile() const {return bitsInReg;}
1399     constexpr int bitsInMemory() const {return bitsInMem;}
1400 };
1401 constexpr DataSize D8(8);
1402 constexpr DataSize D8U32(8, 32);
1403 constexpr DataSize D16U32(16, 32);
1404 constexpr DataSize D16(16);
1405 constexpr DataSize D32(32);
1406 constexpr DataSize D64(64);
1407 
1408 struct DataFormat {
1409     enum class Order {NONTRANSPOSE = 0, TRANSPOSE = 1};
1410     enum class QuadMask {
1411         INVALID = 0,
1412         X = 1, Y = 2, Z = 4, W = 8,
1413         ///////////////////////////////////////////////
1414         // friendly combinations for debugger
1415         XY = X | Y, XZ = X | Z,  XW = X | W,
1416         YZW = W | Z | W, YZ = Y | Z, YW = Y | W,
1417     };
1418 
1419     Order dataOrder;
1420     DataSize dataSize;
1421     int dataElems = 0;
1422     QuadMask dataMask = QuadMask::INVALID; // only for load quad
1423 
1424     constexpr DataFormat(Order ord, DataSize ds, int des = 1)
1425         : dataOrder(ord), dataSize(ds), dataElems(des) { }
1426     constexpr DataFormat(DataSize ds)
1427         : DataFormat(Order::NONTRANSPOSE, ds) { }
1428     constexpr DataFormat(DataSize ds, QuadMask qm)
1429         : DataFormat(Order::NONTRANSPOSE, ds), dataMask(qm),
1430         dataElems(
1431             (int(dataMask) & int(QuadMask::X) ? 1 : 0) +
1432             (int(dataMask) & int(QuadMask::Y) ? 1 : 0) +
1433             (int(dataMask) & int(QuadMask::Z) ? 1 : 0) +
1434             (int(dataMask) & int(QuadMask::W) ? 1 : 0))
1435     {
1436     }
1437 
1438     constexpr int elems() const {return dataElems;}
1439 };
1440 
1441 
1442 struct Format {
1443     const char *description;
1444     const char *canonicalName;
1445     uint32_t encoding;
1446     uint32_t encodingMask;
1447 
1448     SendOp op;
1449     AddrSize addrSize;
1450     DataFormat dataFormat;
1451 
1452     int extraAttrs;
1453 
1454     Doc docs[3];
1455 
1456     constexpr Format(
1457         SendOp o,
1458         const char *desc,
1459         const char *canon,
1460         uint32_t enc, uint32_t encMask,
1461         DataFormat dFormat,
1462         AddrSize aSize,
1463         const Doc &d1 = INVALID_DOC,
1464         const Doc &d2 = INVALID_DOC,
1465         const Doc &d3 = INVALID_DOC)
1466         : op(o)
1467         , description(desc)
1468         , canonicalName(canon)
1469         , encoding(enc)
1470         , encodingMask(encMask)
1471         , dataBitsMemory(dSize)
1472         , dataBitsRegfile(dSize)
1473         , dataVectorSize(1)
1474         , addrBits(aSize)
1475         , extraAttrs(0)
1476     {
1477         docs[0] = d1;
1478         docs[1] = d2;
1479         docs[2] = d3;
1480     }
1481 };
1482 
1483 static constexpr uint32_t DC1_OP_MASK = getFieldMask<uint32_t>(14, 4);
1484 
1485 static constexpr Format DC1_OP(
1486     SendOp op,
1487     const char *desc,
1488     const char *canon,
1489     HDCOpcode enc,
1490     DataSize dSize,
1491     AddrSize aSize,
1492     const Doc &d1 = Doc(),
1493     const Doc &d2 = Doc())
1494 {
1495     return Format(mne, desc, canon, enc, DC1_OP_MASK, dSize, aSize, d1, d2);
1496 }
1497 
1498 static constexpr uint32_t DC0_OP_MASK = getFieldMask<uint32_t>(14, 4);
1499 
1500 static constexpr Format DC0_OP(
1501     SendOp op,
1502     const char *desc,
1503     const char *canon,
1504     HDCOpcode enc,
1505     DataSize dSize,
1506     AddrSize aSize,
1507     const Doc &d1 = Doc(),
1508     const Doc &d2 = Doc())
1509 {
1510     return Format(mne, desc, canon, enc, DC1_OP_MASK, dSize, aSize, d1, d2);
1511 }
1512 
1513 // PROBLEM: how to actually decode all the desc fields...
1514 // (use smaller table groups and match on mask)
1515 static constexpr Format DC1_OPS[] {
1516     // must also decode cmask and BTI
1517     DC1_OP(SendOp::LOAD_QUAD, "untyped surface read", "MSD1R_US",
1518         0x01, D32, A32, "7088", "44747"),
1519     DC1_OP(SendOp::STORE_QUAD, "untyped surface write", "MSD1W_US",
1520         0x09, D32, A32, "7091", "44757"),
1521     DC1_OP(SendOp::LOAD_QUAD, "a64 untyped surface read", "MSD1R_A64_US",
1522         0x11, D32, A64, "7086", "44743"),
1523     DC1_OP(SendOp::STORE_QUAD, "a64 untyped surface write", "MSD1W_A64_US",
1524         0x19, D32, A64, "7089", "44754"),
1525     //
1526     // must also decode vector size and BTI
1527     DC1_OP(SendOp::LOAD, "a64 byte gathering read", "MSD1R_A64_BS",
1528         0x19, D8, A64, "7070"),
1529     DC1_OP(SendOp::STORE, "a64 byte scattering write", "MSD1W_A64_BS",
1530         0x1A, D8, A64, "7073"),
1531 };
1532 static constexpr Format DC0_OPS[] {
1533     DC0_OP(SendOp::LOAD, "byte gathering read", "MSD1R_BS",
1534         0x04, D8, A32, "7066", "44737"),
1535     DC0_OP(SendOp::STORE, "byte scattering write", "MSD1W_BS",
1536         0x0C, D8, A32, "7068", "44748"),
1537     //
1538     // bit [13:12] MBZ, [11:10]
1539     DC0_OP(SendOp::LOAD, "dword gathering read", "MSD0R_DWS",
1540         0x03, D32, A32, "7067", "44738"),
1541     DC0_OP(SendOp::STORE, "dword scattered write", "MSD0W_DWS",
1542         0x0B, D32, A32, "7069", "44749"),
1543     DC0_OP(SendOp::LOAD, "qword gathering read", "MSD0R_QWS",
1544         0x05, D64, A32, "33652", "44742"),
1545     DC0_OP(SendOp::STORE, "qword scattered write", "MSD0W_QWS",
1546         0x0D, D64, A32, "33653", "44753"),
1547 }
1548 #endif // end experimental work
1549 
tryDecodeDC1()1550 void MessageDecoderHDC::tryDecodeDC1() {
1551     const int msgType = getDescBits(14, 5);
1552     switch (msgType)
1553     {
1554     case MSD1R_US: // untyped surface read
1555     case MSD1W_US: // untyped surface write
1556     {
1557         const char *msgName = msgType == MSD1R_US ?
1558             "untyped surface read" : "untyped surface write";
1559         addField("MessageType", 14, 5, msgType, msgName);
1560         //
1561         setHdcUntypedSurfaceMessage(
1562             msgName,
1563             msgType == MSD1R_US,
1564             32,
1565             MessageInfo::Attr::NONE);
1566         setDoc(
1567             msgType == MSD1R_US ? "7088" : "7091",
1568             msgType == MSD1R_US ? "44747" : "44757",
1569             nullptr);
1570         decodeMDC_H();
1571         break;
1572     }
1573     case MSD1R_A64_US: // a64 untype surface read
1574     case MSD1W_A64_US: // a64 untype surface write
1575     {
1576         const char *msgName = msgType == MSD1R_A64_US ?
1577             "a64 untyped surface read" : "a64 untyped surface write";
1578         addField("MessageType", 14, 5, msgType, msgName);
1579         //
1580         setHdcUntypedSurfaceMessage(
1581             msgName,
1582             msgType == MSD1R_A64_US,
1583             64, // 8B addrs
1584             MessageInfo::Attr::NONE);
1585         setDoc(
1586             msgType == MSD1R_A64_US ? "7086" : "7089",
1587             msgType == MSD1R_A64_US ? "44743" : "44754",
1588             nullptr);
1589         decodeMDC_HF();
1590         break;
1591     }
1592     case MSD1R_A64_BS: // a64 gathering read (byte/dw/qw)
1593     case MSD1W_A64_BS: // a64 scattered write (byte/dw/qw)
1594     {
1595         // 0 is byte-scattered, the others (DW/QW) are true SIMT
1596         int subType = getDescBits(8, 2);
1597         bool isRead = msgType == MSD1R_A64_BS;
1598         const auto BYTE_SUBTYPE = 0x0, BSRWSR_SUBTYPE = 0x3;
1599         if (subType == BYTE_SUBTYPE || subType == BSRWSR_SUBTYPE) {
1600             // c.f. handling above with non-A64 version of BSR
1601             const char *msgName = msgType == MSD1R_A64_BS ?
1602                 "a64 byte gathering read" : "a64 byte scattering write";
1603             addField("MessageType", 14, 5, msgType, msgName);
1604             //
1605             if (subType == BYTE_SUBTYPE) {
1606                 addField("SubType", 8, 2, subType, "Byte");
1607                 setDoc(
1608                     msgType == MSD1R_A64_BS ? "7070" : "7073",
1609                     msgType == MSD1R_A64_BS ? "44737" : "44748",
1610                     nullptr);
1611             } else { // subType == 0x3
1612                 addField("SubType", 8, 2, subType, "Byte with Status Return");
1613                 setDoc(msgType == MSD1R_A64_BS ? "19316" : nullptr);
1614                 if (msgType == MSD1W_A64_BS)
1615                     error(14, 5,
1616                         "a64 byte scattering with status return message");
1617             }
1618             //
1619             std::stringstream descs;
1620             descs << msgName;
1621             int bExt = MDC_A64_DS(10);
1622             if (bExt == 1)
1623                 descs << " 8b";
1624             else if (bExt == 2)
1625                 descs << " 16b";
1626             else if (bExt == 4)
1627                 descs << " 32b";
1628             //
1629             setHdcMessageX(
1630                 isRead ? "load" : "store",
1631                 descs.str(),
1632                 isRead ? SendOp::LOAD : SendOp::STORE,
1633                 64, // A64
1634                 32, // widens to DW (similar to non-A64 version)
1635                 8*bExt, // bits from memory
1636                 1, //
1637                 decodeMDC_SM2(12),
1638                 MessageInfo::Attr::NONE);
1639         } else {
1640             const auto DW_SUBTYPE = 0x1;
1641             const auto QW_SUBTYPE = 0x2;
1642             bool isDword = subType == DW_SUBTYPE; // else QW
1643             // unlike non-A64 version, this variant supports DW and QW
1644             // in the same message type, the MDC_A64_DS is treated as a
1645             // vector length
1646             const char *msgTypeName = msgType == MSD1R_A64_BS ?
1647                 "a64 gathering read" : "a64 scattering write";
1648             addField("MessageType", 14, 5, msgType, msgTypeName);
1649             //
1650             const char *msgName =
1651                 isDword ?
1652                     (isRead ?
1653                         "a64 dword gathering read" :
1654                         "a64 dword scattering write") :
1655                     (isRead ?
1656                         "a64 qword gathering read" :
1657                         "a64 qword scattering write");
1658             //
1659             int elemsPerAddr = decodeMDC_DWS_DS(10);
1660             std::stringstream ss;
1661             if (elemsPerAddr != 1)
1662                 ss << msgName << " x" << elemsPerAddr;
1663             //
1664             addField(
1665                 "SubType", 8, 2, subType, subType == 1 ? "DWord" : "QWord");
1666             //
1667             setHdcMessage(
1668                 isRead ? "load" : "store",
1669                 msgName,
1670                 isRead ? SendOp::LOAD : SendOp::STORE,
1671                 64,
1672                 isDword ? 32 : 64,
1673                 elemsPerAddr, // true vector
1674                 decodeMDC_SM2(12),
1675                 MessageInfo::Attr::NONE);
1676             if (isDword) {
1677                 setDoc(
1678                     isRead ? "7071" : "7074",
1679                     isRead ? "44738" : "44749",
1680                     nullptr);
1681             } else {
1682                 setDoc(isRead ? "7072" : "7075");
1683             }
1684         }
1685         result.info.cachingL3 = decodeMDC_IAR();
1686         decodeMDC_HF();
1687         break;
1688     }
1689     case MSD1R_A64_HWB: // a64 [un]aligned (hword|oword) block read
1690     case MSD1W_A64_HWB: // a64 [un]aligned (hword|oword) block write
1691     {
1692         bool isRead = msgType == MSD1R_A64_HWB;
1693 
1694         addField("MessageType", 14, 5, msgType,
1695             isRead ? "a64 block read" :"a64 block write");
1696         bool isHword = false;
1697         bool isUnaligned = false;
1698         auto subType = decodeDescField("SubType", 11, 2,
1699             [&] (std::stringstream &ss, uint32_t val) {
1700                 switch (val) {
1701                 case 0x0:
1702                     isUnaligned = true;
1703                     ss << "oword unaligned";
1704                     break;
1705                 case 0x1:
1706                     ss << "oword aligned";
1707                     break;
1708                 case 0x3:
1709                     isHword = true;
1710                     isUnaligned = true;
1711                     ss << "hword unaligned";
1712                     break;
1713                     //
1714                 default:
1715                     ss << "dual block";
1716                     isUnaligned = true;
1717                     error(11, 2, "a64 dual block read/write unsupported");
1718                     break;
1719                 }
1720             });
1721 
1722         if (isHword && isUnaligned)
1723             setDoc(
1724                 isRead ? "7034" : "7038", isRead ? "44739" : "44750", nullptr);
1725         else if (isHword && !isUnaligned) {
1726             bool supported = platform() >= Platform::XE_HPG;
1727             setDoc(isRead ? "20861" : "20862");
1728             if (!supported)
1729                 error(11, 2, "HWord aligned unsupported on this platform");
1730         } else if (!isHword && isUnaligned) {
1731             setDoc(
1732                 isRead ? "7037" : "33440",
1733                 isRead ? "44740" : "44751",
1734                 nullptr); // MSD1R_A64_OWAB|MSD1W_A64_OWAB
1735         } else if (!isHword && !isUnaligned) {
1736             setDoc(
1737                 isRead ? "7039" : "7039",
1738                 isRead ? "44741" : "44752",
1739                 nullptr); // MSD1R_A64_OWB|MSD1W_A64_OWB
1740         } else if (subType == 2) {
1741             setDoc(isRead ? "7036" : "7040");
1742             result.info.description = "a64 dual block ";
1743             result.info.description += (isRead ? " read" : " write");
1744             result.info.symbol =
1745                 isRead ? "MSD1R_A64_OWDB" : "MSD1W_A64_OWDB";
1746             result.info.addrSizeBits = 64;
1747             decodeMDC_HR();
1748             break; // dual block (error)
1749         }
1750         //
1751         std::string msgSym = isRead ? "load_block" : "store_block";
1752         std::string msgDesc = "a64";
1753         if (isUnaligned) {
1754             msgDesc += " unaligned";
1755         } else {
1756             msgDesc += " aligned";
1757             msgSym += "_aligned";
1758         }
1759         if (isHword) {
1760             msgDesc += " hword";
1761         } else {
1762             msgDesc += " oword";
1763         }
1764         msgDesc += " block";
1765         if (msgType == 0x14) {
1766             msgDesc += " read";
1767         } else {
1768             msgDesc += " write";
1769         }
1770         if (isHword) {
1771             setHdcHwBlock(
1772                 msgSym,
1773                 msgDesc,
1774                 isRead ? SendOp::LOAD : SendOp::STORE,
1775                 64, // 64b addr
1776                 8, 3, // offset of HWs
1777                 MessageInfo::Attr::NONE);
1778         } else {
1779             setHdcOwBlock(
1780                 msgSym,
1781                 msgDesc,
1782                 isRead ? SendOp::LOAD : SendOp::STORE,
1783                 64, // 64b addr
1784                 MessageInfo::Attr::NONE);
1785         }
1786         result.info.cachingL3 = decodeMDC_IAR();
1787         decodeMDC_HR(); // all block require a header
1788         break;
1789     }
1790     case MSD1W_A64_DWAF: // a64 untyped fp32 atomic
1791         setHdcFloatAtomicMessage(
1792             "a64 float atomic",
1793             64,
1794             32,
1795             "7126", "7118",
1796             "44682", "44649");
1797         decodeMDC_HF();
1798         break;
1799 
1800     case MSD1W_DWAF: // a32 untyped fp32 atomic
1801         setHdcFloatAtomicMessage(
1802             "float atomic",
1803             32,
1804             32,
1805             "7130", "7122",
1806             "44697", "44664");
1807         decodeMDC_H();
1808         break;
1809     case MSD1W_A64_AI: // a64 untyped atomic int{32,64}
1810     {
1811         // the encoding repurposes the SIMD size as the data size and the
1812         // message and thus the SIMD size is always fixed
1813         int simd = platform() >= Platform::XE_HPC ? 16 : 8;
1814         auto is64b =
1815             decodeDescBitField("DataWidth", 12, "32b", "64b");
1816         const char *msgName = is64b ?
1817             "a64 atomic int64" : "a64 atomic int32";
1818         const char *docNoRet = is64b ? "7161" : "7155";
1819         const char *docNoRetXe = is64b ? "44688" : "44685";
1820         const char *docWiRet = is64b ? "7143" : "7137";
1821         const char *docWiRetXe = is64b ? "44655" : "44652";
1822         //
1823         setHdcIntAtomicMessage(
1824             "untyped",
1825             msgName,
1826             64,
1827             is64b ? 64 : 32,
1828             simd,
1829             docNoRet, docWiRet,
1830             docNoRetXe, docWiRetXe);
1831         decodeMDC_HF();
1832         break;
1833     }
1834     case MSD1W_DWAI: // atomic int32
1835     {
1836         const char *msgName = "untyped atomic int32";
1837         addField("MessageType", 14, 5, msgType, msgName);
1838         //
1839         setHdcIntAtomicMessage(
1840             "untyped",
1841             "atomic int32",
1842             32,
1843             32,
1844             decodeMDC_SM2R(12),
1845             "7167", "7149",
1846             "44700", "44667");
1847         decodeMDC_H();
1848         break;
1849     }
1850     case MSD1R_MB: // media block read
1851     case MSD1W_MB: // media block write
1852     {
1853         std::stringstream sym, descs;
1854         sym << "mb";
1855         descs << "media block ";
1856         int bytesTransmitted = 0;
1857         if (msgType == MSD1R_MB) {
1858             descs << "read";
1859             sym << "rd";
1860             bytesTransmitted = 2*DEFAULT_EXEC_SIZE*getDescBits(20,5);
1861         } else {
1862             descs << "write";
1863             sym << "wr";
1864             int mlen = getDescBits(25, 4);
1865             if (mlen == 0) {
1866                 error(25, 4, "mlen == 0 on write");
1867             } else {
1868                 bytesTransmitted = 2*DEFAULT_EXEC_SIZE*(mlen - 1);
1869             }
1870         }
1871         int vlso = getDescBits(8, 3); // [10:8] is vert. line stride overr.
1872         if (vlso) {
1873             descs << " with vertical line stride ";
1874             int n = 0;
1875             if (vlso & 0x2) {
1876                 descs << "override";
1877                 n++;
1878             }
1879             if (vlso & 0x1) {
1880                 if ((vlso & 0x2) == 0)
1881                     descs << " and ";
1882                 else if (n > 0)
1883                     descs << ",";
1884                 descs << "skip";
1885                 n++;
1886             }
1887             if (vlso & 0x2) {
1888                 if (n >= 2)
1889                     descs << ", and ";
1890                 else if (n > 0)
1891                     descs << " and ";
1892                 descs << "offset";
1893                 n++;
1894                 if ((vlso & 0) == 0) {
1895                     warning(8, 3,
1896                         "stride offset meaningless when override not set");
1897                 }
1898             }
1899         }
1900         setHdcMessage(sym.str(), descs.str(),
1901             msgType == 0x4 ? SendOp::LOAD : SendOp::STORE,
1902             32, 8, bytesTransmitted, 1,
1903             MessageInfo::Attr::TRANSPOSED);
1904         setDoc(
1905             msgType == MSD1R_MB ? "7046" : "7048",
1906             msgType == MSD1R_MB ? "44744" : "44755",
1907             nullptr);
1908         decodeMDC_HR();
1909         break;
1910     }
1911     case MSD1R_TS: // typed surface read
1912         setHdcTypedSurfaceMessage(true, "7087", "44745");
1913         decodeMDC_H();
1914         break;
1915     case MSD1W_TS: // typed surface write
1916         setHdcTypedSurfaceMessage(false, "7090", "44756");
1917         decodeMDC_H();
1918         break;
1919     case MSD1RS_TS: // typed surface read with status
1920         setHdcTypedSurfaceMessage(true, "19315", "44735", true);
1921         decodeMDC_H();
1922         break;
1923     case MSD1A_DWAC:
1924         setHdcIntAtomicMessage(
1925             "typed",
1926             "atomic 32-bit counter",
1927             32, // addrSize
1928             32, // dataSize
1929             decodeMDC_SM2R(12),
1930             "7109", "7099",
1931             "44696", "44663");
1932         decodeMDC_HR();
1933         result.info.attributeSet |= MessageInfo::Attr::HAS_UVRLOD;
1934         break;
1935     case MSD1A_DWTAI:
1936     {
1937         bool sgh = decodeMDC_SG2();
1938         setHdcIntAtomicMessage(
1939             sgh ? "typed_sgh" : "typed" ,
1940             sgh ?
1941                 "atomic 32-bit integer (slot group high)" :
1942                 "atomic 32-bit integer",
1943             32, // addrSize
1944             32, // dataSize
1945             DEFAULT_EXEC_SIZE / 2,
1946             "7113", "7103",
1947             "44703","44670");
1948         decodeMDC_H();
1949         break;
1950     }
1951     case MSD1A_WAC:
1952         setHdcIntAtomicMessage(
1953             "typed",
1954             "atomic 16-bit counter",
1955             32, // addrSize
1956             16, // dataSize
1957             decodeMDC_SM2R(12),
1958             "21412","21411",
1959             "44706", "44673");
1960         decodeMDC_HR();
1961         result.info.attributeSet |= MessageInfo::Attr::HAS_UVRLOD;
1962         break;
1963     case MSD1A_WTAI:
1964     {
1965         bool sgh = decodeMDC_SG2();
1966         setHdcIntAtomicMessage(
1967             sgh ?
1968             "typed_sgh" :
1969             "typed",
1970             sgh ?
1971             "atomic 16-bit integer (slot group high)" :
1972             "atomic 16-bit integer",
1973             32, // addrSize
1974             16, // dataSize
1975             DEFAULT_EXEC_SIZE / 2,
1976             "21416", "21415",
1977             "44703", "44670");
1978         decodeMDC_H();
1979         result.info.attributeSet |= MessageInfo::Attr::HAS_UVRLOD;
1980         break;
1981     }
1982     case MSD1A_A64_WAF: // a64 fp16 atomic
1983     case MSD1A_WAF: // fp16 atomic
1984     {
1985         if (platform() <= Platform::GEN11) {
1986             // these used to be SIMD4x2
1987             error(14, 5, "SIMD4x2 atomic float decode unsupported");
1988             return;
1989         }
1990         bool isA64 = msgType == MSD1A_A64_WAF;
1991         setHdcFloatAtomicMessage(
1992             isA64 ?
1993             "a64 untyped half-float atomic" : "untyped half-float atomic",
1994             isA64 ? 64 : 32,
1995             16,
1996             isA64 ? "21405" : "21407", isA64 ? "21404" : "21406",
1997             isA64 ? "44690" : "54102", isA64 ? "44657" : "54101");
1998         if (isA64)
1999             decodeMDC_HF();
2000         else
2001             decodeMDC_H();
2002         break;
2003     }
2004     case MSD1A_A64_WAI: // a64 int16 atomic
2005     case MSD1A_WAI: // int16 atomic
2006     {
2007         if (platform() <= Platform::GEN11) {
2008             // these used to be SIMD4x2
2009             error(14, 5, "SIMD4x2 atomic int decode unsupported");
2010             return;
2011         }
2012         bool isA64 = msgType == MSD1A_A64_WAI;
2013         setHdcIntAtomicMessage(
2014             "untyped",
2015             isA64 ? "a64 atomic int16" : "atomic int16",
2016             msgType == MSD1A_A64_WAI ? 64 : 32,
2017             16,
2018             decodeMDC_SM2R(12),
2019             isA64 ? "21390" : "21396", isA64 ? "21389" : "21397",
2020             isA64 ? "44693" : "44710", isA64 ? "44660" : "44677");
2021         if (isA64)
2022             decodeMDC_HF();
2023         else
2024             decodeMDC_H();
2025         break;
2026     }
2027     default:
2028         error(14, 5, "unsupported DC1 op");
2029         return;
2030     } // DC1 switch
2031 }
2032 
2033 
decodeDescriptorsHDC(Platform platform,SFID sfid,ExecSize execSize,SendDesc exDesc,SendDesc desc,DecodeResult & result)2034 void iga::decodeDescriptorsHDC(
2035     Platform platform, SFID sfid, ExecSize execSize,
2036     SendDesc exDesc, SendDesc desc,
2037     DecodeResult &result)
2038 {
2039     MessageDecoderHDC mdo(
2040         platform, sfid, execSize,
2041         exDesc, desc, result);
2042     mdo.tryDecode();
2043 }
2044 
2045