1 /*========================== begin_copyright_notice ============================
2 
3 Copyright (C) 2021 Intel Corporation
4 
5 SPDX-License-Identifier: MIT
6 
7 ============================= end_copyright_notice ===========================*/
8 
9 #ifndef G4_SEND_DESCS_HPP
10 #define G4_SEND_DESCS_HPP
11 
12 #include "Common_ISA.h"
13 
14 #include <string>
15 #include <ostream>
16 #include <utility>
17 
18 namespace vISA
19 {
20 enum class SendAccess
21 {
22     INVALID = 0,
23     READ_ONLY, // e.g. load
24     WRITE_ONLY, // e.g. store
25     READ_WRITE // e.g. an atomic with return
26 };
27 static const int LDST_LOAD_GROUP   = 0x100;
28 static const int LDST_STORE_GROUP  = 0x200;
29 static const int LDST_ATOMIC_GROUP = 0x400;
30 static const int LDST_OTHER_GROUP  = 0x800;
31 //
32 // load/store operation
33 enum class LdStOp {
34     INVALID = 0,
35     //
36     LOAD = LDST_LOAD_GROUP + 1,
37     LOAD_QUAD, // e.g. untyped load (loading XYZW)
38     LOAD_STRIDED, // same as load, but 1 address (obeys exec mask)
39     LOAD_BLOCK2D,
40     //
41     STORE_GROUP = LDST_STORE_GROUP + 1,
42     STORE,
43     STORE_QUAD,
44     STORE_STRIDED,
45     STORE_BLOCK2D,
46     //
47     // atomics
48     ATOMIC_GROUP = LDST_ATOMIC_GROUP + 1,
49     ATOMIC_LOAD,
50     ATOMIC_STORE,
51     //
52     ATOMIC_FADD,
53     ATOMIC_FSUB,
54     ATOMIC_FMIN,
55     ATOMIC_FMAX,
56     ATOMIC_FCAS,
57     //
58     ATOMIC_IINC,
59     ATOMIC_IDEC,
60     ATOMIC_IADD,
61     ATOMIC_ISUB,
62     ATOMIC_ICAS,
63     ATOMIC_SMIN,
64     ATOMIC_SMAX,
65     ATOMIC_UMIN,
66     ATOMIC_UMAX,
67     //
68     ATOMIC_AND,
69     ATOMIC_XOR,
70     ATOMIC_OR,
71     // others ...
72 };
73 std::string ToSymbol(LdStOp);
74 
75 enum class LdStOrder {
76     INVALID = 0,
77     //
78     SCALAR, // aka "transposed", typically SIMD1, should be (W)
79     VECTOR, // normal vector message or atomic (honors the execution mask)
80 };
81 enum class AddrType {
82     INVALID = 0,
83     //
84     FLAT,
85     SS, BSS,
86     BTI
87 };
88 
89 // Cache controls
90 // only certain combinations are legal
91 enum class Caching {
92     // the invalid value for caching
93     INVALID = 0,
94     //
95     CA, // cached (load)
96     DF, // default (load/store)
97     RI, // read-invalidate (load)
98     WB, // writeback (store)
99     UC, // uncached (load)
100     ST, // streaming (load/store)
101     WT, // writethrough (store)
102 };
103 std::string ToSymbol(Caching);
104 // default, default returns ""
105 std::string ToSymbol(Caching,Caching);
106 
107 struct ImmOff {
108     bool is2d;
109     union {
110         int immOff;
111         struct {short immOffX, immOffY;};
112     };
ImmOffvISA::ImmOff113     ImmOff(int imm) : is2d(false), immOff(imm) { }
ImmOffvISA::ImmOff114     ImmOff(short immX, short immY) : is2d(true), immOffX(immX), immOffY(immY) { }
ImmOffvISA::ImmOff115     ImmOff() : ImmOff(0) { }
116 };
117 
118 enum class LdStAttrs {
119     NONE = 0,
120     //
121     // for atomic messages that don't indicate if the return value is used
122     ATOMIC_RETURN   = 0x0001,
123     //
124     // for cases where the message does not imply if it is a scratch access
125     SCRATCH_SURFACE = 0x0002,
126 };
operator |(LdStAttrs a0,LdStAttrs a1)127 static inline LdStAttrs operator|(LdStAttrs a0, LdStAttrs a1) {
128     return LdStAttrs(int(a0) | int(a1));
129 }
130 
131 // Abstraction for the nubmer of elements each address loads.
132 // Generally this is just a simple value (e.g. V4 would be 4), but we
133 // also support the channel mask nonsense added by LOAD_QUAD, STORE_QUAD.
134 struct ElemsPerAddr {
135     // A friendly four-element bitset that is inductively closed and
136     // correct under the custom | operator below
137     enum class Chs {
138         INVALID = 0,
139         //
140         X = 1,
141         Y = 2,
142         Z = 4,
143         W = 8,
144         //
145         XY   = X | Y,
146         XZ   = X     | Z,
147         XW   = X         | W,
148         XYZ  = X | Y | Z,
149         XYW  = X | Y     | W,
150         XZW  = X     | Z | W,
151         XYZW = X | Y | Z | W,
152         //
153         YZ   =     Y | Z,
154         YW   =     Y     | W,
155         YZW  =     Y | Z | W,
156         //
157         ZW  =          Z | W,
158     };
159 
160     // works on both channel masks and vector lengths
161     int getCount() const;
162 
isChannelMaskvISA::ElemsPerAddr163     bool isChannelMask() const {return isChMask;}
164 
165     // asserts if not isChannelMask()
166     Chs getMask() const;
167 
168     std::string str() const;
169 
ElemsPerAddrvISA::ElemsPerAddr170     ElemsPerAddr(int _count) : isChMask(false), count(_count) { }
ElemsPerAddrvISA::ElemsPerAddr171     ElemsPerAddr(Chs chs) : isChMask(true), channels(chs) { }
172 private:
173     bool isChMask;
174     union {
175         int count;
176         Chs channels;
177     };
178 }; // ElemsPerAddr
operator |(ElemsPerAddr::Chs c0,ElemsPerAddr::Chs c1)179 static inline ElemsPerAddr::Chs operator|(
180     ElemsPerAddr::Chs c0, ElemsPerAddr::Chs c1)
181 {
182     return ElemsPerAddr::Chs(int(c0) | int(c1));
183 }
184 
185 
186 class G4_Operand;
187 
188 // Base class for all send descriptors.
189 // (Note that G4_SendDesc could be reused by more than one instruction.)
190 class G4_SendDesc
191 {
192     friend class G4_InstSend;
193 
194 protected:
195     // The execution size for this message.
196     G4_ExecSize execSize;
197 
198     // Limit access to G4_InstSend and any derived classes.
setExecSize(G4_ExecSize v)199     void setExecSize(G4_ExecSize v) { execSize = v; }
200 
201 public:
202     enum class Kind {INVALID, RAW, LDST};
203 
204     Kind        kind;
205 
206     SFID        sfid;
207 
G4_SendDesc(Kind k,SFID _sfid)208     G4_SendDesc(Kind k, SFID _sfid) : kind(k), sfid(_sfid), execSize(g4::SIMD_UNDEFINED) { }
G4_SendDesc(Kind k,SFID _sfid,G4_ExecSize _execSize)209     G4_SendDesc(Kind k, SFID _sfid, G4_ExecSize _execSize)
210         : kind(k),
211           sfid(_sfid),
212           execSize(_execSize)
213     {}
214 
getSFID() const215     SFID getSFID() const {return sfid;}
216 
217     // execSize: need to set it in the ctor
getExecSize() const218     G4_ExecSize getExecSize() const { return execSize; }
219 
isRaw() const220     bool isRaw() const {return kind == Kind::RAW;}
isLdSt() const221     bool isLdSt() const {return kind == Kind::LDST;}
222     //
223     bool isHDC() const;
224     bool isLSC() const;
isSampler() const225     bool isSampler() const {return getSFID() == SFID::SAMPLER;}
226     //
227     virtual bool isEOT() const = 0;
228     virtual bool isSLM() const = 0;
229     virtual bool isTyped() const = 0;
230     virtual bool isAtomic() const = 0;
231     virtual bool isBarrier() const = 0;
232     virtual bool isFence() const = 0;
233     //
234     // This gives a general access type
235     virtual SendAccess getAccessType() const = 0;
isRead() const236     bool isRead() const {
237         return
238             getAccessType() == SendAccess::READ_ONLY ||
239             getAccessType() == SendAccess::READ_WRITE;
240     }
isWrite() const241     bool isWrite() const {
242         return
243             getAccessType() == SendAccess::WRITE_ONLY ||
244             getAccessType() == SendAccess::READ_WRITE;
245     }
isReadWrite() const246     bool isReadWrite() const {
247         return getAccessType() == SendAccess::READ_WRITE;
248     }
249     //
250     // Returns the caching behavior of this message if known.
251     // Returns Caching::INVALID if the message doesn't support caching
252     // controls.
253     virtual std::pair<Caching,Caching> getCaching() const = 0;
getCachingL1() const254     Caching getCachingL1() const {return getCaching().first;}
getCachingL3() const255     Caching getCachingL3() const {return getCaching().second;}
256     virtual void setCaching(Caching l1, Caching l3) = 0;
257     //
258     // generally in multiples of full GRFs, but a few exceptions such
259     // as OWord and HWord operations may make this different
260     virtual size_t getDstLenBytes() const = 0;
261     virtual size_t getSrc0LenBytes() const = 0;
262     virtual size_t getSrc1LenBytes() const = 0;
263     //
264     // These round up to the nearest register.
265     // For legacy uses (e.g. MessageLength, exMessageLength(), ...)
266     // (e.g. an OWord block read will report 1 register)
267     // Favor the get{Dst,Src0,Src1}LenBytes() methods.
268     size_t getDstLenRegs() const;
269     size_t getSrc0LenRegs() const;
270     size_t getSrc1LenRegs() const;
271     //
272     // true if the message is a scratch space access (e.g. scratch block read)
273     virtual bool isScratch() const = 0;
274     //
isScratchRead() const275     bool isScratchRead() const{return isScratch() && isRead();}
isScratchWrite() const276     bool isScratchWrite() const {return isScratch() && isWrite();}
277     //
278     // message offset in terms of bytes
279     //   e.g. scratch offset
280     virtual int getOffset() const = 0;
281 
282     // Returns the associated surface (if any)
283     // This can be a BTI (e.g. a0 register or G4_Imm if immediate)
284     virtual G4_Operand *getSurface() const = 0;
285 
286     virtual std::string getDescription() const = 0;
287 };
288 
289 
290 ///////////////////////////////////////////////////////////////////////////////
291 // high-level load/store descriptors
292 
293 //
294 // A Load/Store message descriptor
295 // Unlike G4_SendDescRaw, this descriptor will be encoded by the
296 // IGA adapter or further back.
297 //
298 // Just because you can specify it here does not mean there's a valid message.
299 // Check canEncode().
300 struct G4_SendDescLdSt : G4_SendDesc {
301     // The message op
302     LdStOp op;
303 
304     // E.g. flat, bti, ...
305     AddrType addrType;
306     //
307     // e.g. 64 for A64, 32 for A32
308     int addrBits;
309     //
310     // Untyped linear acccesses will have 1 (general case)
311     // Typed messages can have 1-4.
312     // Any two dimensions block opreations will have 2.
313     int addrDims;
314 
315     //
316     // The number of bits per element loaded from memory by this message.
317     //   E.g. D32 would be 32
318     //   E.g. D8U32 ==> 8
319     int elemBitsMem;
320     //
321     // The number of bits each element occupies in the register file
322     // This is generally the same as memory with minor exceptions for aligned
323     // loads (e.g. byte scattered loads that align bytes or words to 32b)
324     // e.g. D8U32 has 32 for this and 8 for `elemBitsMem`
325     int elemBitsReg;
326     //
327     // The number of elements we load per address.
328     //   e.g. D32V4 would be 4
329     //   for load_quad/store_quad this will be 1, 2, 3, 4
330     //     e.g. V3 would imply .XYZ
331     //   exotic strided load_quad stuff like .ZW is illegal
332     //   i.e. we only support .X, .XY, .XYZ, and .XYZW
333     int elemPerAddr;
334     //
335     // The data order message kind
336     LdStOrder order; // "transposed" ==> 1 address
337 
338     // The caching options for L1 and L3
339     Caching l1, l3;
340 
341     // an immediate offset to add to each element (if supported)
342     ImmOff immOff;
343 
344     // For messages that take a surface (e.g. a0.#)
345     //  This must be either:
346     //    - nullptr for FLAT messages such as stateless global memory or SLM
347     //    - reference to an a0.# register
348     //    - an immediate value (for an immediate BTI)
349     //    - for BSS/SS this is a reference to an a0 register
350     G4_Operand *surface = nullptr;
351 
352     // Other miscellaneous attributes that cannot be deduced from the
353     // information above
354     LdStAttrs attrs;
355 
356     // In some rare cases we must explicitly override message payload sizes.
357     //    1. prefetches use a null dst and set rLen = 0
358     //    2. e.g. block2d puts block sizes in a header
359     short overrideDstLengthBytesValue = -1;
360     short overrideSrc0LengthBytesValue = -1;
361     short overrideSrc1LengthBytesValue = -1;
362 
363     G4_SendDescLdSt(
364         SFID sfid,
365         LdStOp _op,
366         G4_ExecSize _execSize,
367         //
368         // addr params
369         AddrType at, int _addrBits, int _addrDims,
370         //
371         // data params
372         int elemBitsMem, int elemBitsReg, int elemsPerAddr,
373         LdStOrder _order,
374         //
375         // ext info
376         Caching _l1, Caching _l3,
377         G4_Operand *surf,
378         ImmOff _immOff,
379         LdStAttrs _attrs);
380 
operator newvISA::G4_SendDescLdSt381     void *operator new(size_t sz, Mem_Manager &m) { return m.alloc(sz); }
382 
383     ///////////////////////////////////////////////////////////////////////////
384     // queries (getters)
385 
386     // Checks if a message has a valid encoding on the current platform
387     // an optional error diagnostic can give you a failure hint.
388     bool canEncode(std::string *error = nullptr) const;
389 
hasAttrsvISA::G4_SendDescLdSt390     bool hasAttrs(LdStAttrs a) const {
391         return (int(a) & int(attrs)) == int(a);
392     }
393 
394     virtual size_t getSrc0LenBytes() const override;
395     virtual size_t getSrc1LenBytes() const override;
396     virtual size_t getDstLenBytes() const override;
397 
398     virtual SendAccess getAccessType() const override;
getCachingvISA::G4_SendDescLdSt399     virtual std::pair<Caching,Caching> getCaching() const override {return std::make_pair(l1, l3);}
400     virtual void setCaching(Caching l1, Caching l3) override;
401     //
getOffsetvISA::G4_SendDescLdSt402     virtual int getOffset() const override {return immOff.immOff;}
getSurfacevISA::G4_SendDescLdSt403     virtual G4_Operand *getSurface() const override {return surface;}
404     //
isEOTvISA::G4_SendDescLdSt405     virtual bool isEOT() const override {return false;}
406     virtual bool isSLM() const override;
407     virtual bool isAtomic() const override;
isBarriervISA::G4_SendDescLdSt408     virtual bool isBarrier() const override {return false;}
isFencevISA::G4_SendDescLdSt409     virtual bool isFence() const override {return false;}
isScratchvISA::G4_SendDescLdSt410     virtual bool isScratch() const override {return hasAttrs(LdStAttrs::SCRATCH_SURFACE);}
411     virtual bool isTyped() const override;
412 
getDescriptionvISA::G4_SendDescLdSt413     virtual std::string getDescription() const override {return str();}
414     void str(std::ostream &os) const;
415     std::string str() const;
416 
417     ///////////////////////////////////////////////////////////////////////////
418     // mutators (setters)
overrideSrc0LengthBytesvISA::G4_SendDescLdSt419     void overrideSrc0LengthBytes(size_t lenBytes) {
420         MUST_BE_TRUE(lenBytes == (size_t)-1 || lenBytes <= (1 << 15) - 1,
421             "value out of range");
422         overrideSrc0LengthBytesValue = lenBytes;
423     }
overrideSrc1LengthBytesvISA::G4_SendDescLdSt424     void overrideSrc1LengthBytes(size_t lenBytes) {
425         MUST_BE_TRUE(lenBytes == (size_t)-1 || lenBytes <= (1 << 15) - 1,
426             "value out of range");
427         overrideSrc1LengthBytesValue = lenBytes;
428     }
overrideDstLengthBytesvISA::G4_SendDescLdSt429     void overrideDstLengthBytes(size_t lenBytes) {
430         MUST_BE_TRUE(lenBytes == (size_t)-1 || lenBytes <= (1 << 15) - 1,
431             "value out of range");
432         overrideDstLengthBytesValue = lenBytes;
433     }
434 }; // G4_SendDescLdSt
435 
436 
437 ////////////////////////////////////////////////////////////////////////////
438 class IR_Builder;
439 
440 class G4_SendDescRaw : public G4_SendDesc
441 {
442 private:
443     /// Structure describes a send message descriptor. Only expose
444     /// several data fields; others are unnamed.
445     struct MsgDescLayout {
446         uint32_t funcCtrl : 19;     // Function control (bit 0:18)
447         uint32_t headerPresent : 1; // Header present (bit 19)
448         uint32_t rspLength : 5;     // Response length (bit 20:24)
449         uint32_t msgLength : 4;     // Message length (bit 25:28)
450         uint32_t simdMode2 : 1;     // 16-bit input (bit 29)
451         uint32_t returnFormat : 1;  // 16-bit return (bit 30)
452         uint32_t EOT : 1;           // EOT
453     };
454 
455     /// View a message descriptor in two different ways:
456     /// - as a 32-bit unsigned integer
457     /// - as a structure
458     /// This simplifies the implementation of extracting subfields.
459     union DescData {
460         uint32_t value;
461         MsgDescLayout layout;
462     } desc;
463 
464     /// Structure describes an extended send message descriptor.
465     /// Only expose several data fields; others are unnamed.
466     struct ExtendedMsgDescLayout {
467         uint32_t funcID : 4;       // bit 0:3
468         uint32_t unnamed1 : 1;     // bit 4
469         uint32_t eot : 1;          // bit 5
470         uint32_t extMsgLength : 5; // bit 6:10
471         uint32_t cps : 1;          // bit 11
472         uint32_t RTIndex : 3;      // bit 12-14
473         uint32_t src0Alpha : 1;    // bit 15
474         uint32_t extFuncCtrl : 16; // bit 16:31
475     };
476 
477     /// View an extended message descriptor in two different ways:
478     /// - as a 32-bit unsigned integer
479     /// - as a structure
480     /// This simplifies the implementation of extracting subfields.
481     union ExtDescData {
482         uint32_t value;
483         ExtendedMsgDescLayout layout;
484     } extDesc;
485 
486     SendAccess accessType;
487 
488     /// Whether funcCtrl is valid
489     bool funcCtrlValid;
490 
491     // sampler surface pointer?
492     G4_Operand *m_sti;
493     G4_Operand *m_bti; // BTI or other surface pointer
494 
495     /// indicates this message is an LSC message
496     bool        isLscDescriptor = false;
497     // sfid now stored separately from the ExDesc[4:0] since the new LSC format
498     // no longer uses ExDesc for that information
499     int         src1Len;
500     bool        eotAfterMessage = false;
501 
502 public:
503     static const int SLMIndex = 0xFE;
504 
505     G4_SendDescRaw(
506         uint32_t fCtrl, uint32_t regs2rcv, uint32_t regs2snd,
507         SFID fID, uint16_t extMsgLength, uint32_t extFCtrl,
508         SendAccess access, G4_Operand* bti, G4_Operand* sti, IR_Builder& builder);
509 
510     /// Construct a object with descriptor and extended descriptor values.
511     /// used in IR_Builder::createSendMsgDesc(uint32_t desc, uint32_t extDesc, SendAccess access)
512     G4_SendDescRaw(
513         uint32_t desc, uint32_t extDesc, SendAccess access,
514         G4_Operand* bti, G4_Operand* sti);
515 
516     /// Preferred constructor takes an explicit SFID and src1 length
517     G4_SendDescRaw(
518         SFID sfid,
519         uint32_t desc,
520         uint32_t extDesc,
521         int src1Len,
522         SendAccess access,
523         G4_Operand *bti,
524         bool isValidFuncCtrl);
525 
526     // Preferred constructor takes an explicit SFID and src1 length
527     // Need execSize, so it is created for a particular send.
528     G4_SendDescRaw(
529         SFID sfid,
530         uint32_t desc,
531         uint32_t extDesc,
532         int src1Len,
533         SendAccess access,
534         G4_Operand* bti,
535         G4_ExecSize execSize,
536         bool isValidFuncCtrl);
537 
operator new(size_t sz,Mem_Manager & m)538     void *operator new(size_t sz, Mem_Manager &m) { return m.alloc(sz); }
539 
createExtDesc(SFID funcID,bool isEot=false)540     static uint32_t createExtDesc(SFID funcID, bool isEot = false)
541     {
542         return createExtDesc(funcID, isEot, 0, 0);
543     }
544 
createMRTExtDesc(bool src0Alpha,uint8_t RTIndex,bool isEOT,uint32_t extMsgLen,uint16_t extFuncCtrl)545     static uint32_t createMRTExtDesc(bool src0Alpha, uint8_t RTIndex, bool isEOT, uint32_t extMsgLen, uint16_t extFuncCtrl)
546     {
547         ExtDescData data;
548         data.value = 0;
549         data.layout.funcID = SFIDtoInt(SFID::DP_WRITE);
550         data.layout.RTIndex = RTIndex;
551         data.layout.src0Alpha = src0Alpha;
552         data.layout.eot = isEOT;
553         data.layout.extMsgLength = extMsgLen;
554         data.layout.extFuncCtrl = extFuncCtrl;
555         return data.value;
556     }
557 
createExtDesc(SFID funcID,bool isEot,unsigned extMsgLen,unsigned extFCtrl=0)558     static uint32_t createExtDesc(SFID funcID,
559         bool isEot,
560         unsigned extMsgLen,
561         unsigned extFCtrl = 0)
562     {
563         ExtDescData data;
564         data.value = 0;
565         data.layout.funcID = SFIDtoInt(funcID);
566         data.layout.eot = isEot;
567         data.layout.extMsgLength = extMsgLen;
568         data.layout.extFuncCtrl = extFCtrl;
569         return data.value;
570     }
571 
createDesc(uint32_t fc,bool headerPresent,unsigned msgLength,unsigned rspLength)572     static uint32_t createDesc(uint32_t fc, bool headerPresent,
573         unsigned msgLength, unsigned rspLength)
574     {
575         DescData data;
576         data.value = fc;
577         data.layout.headerPresent = headerPresent;
578         data.layout.msgLength = static_cast<uint16_t>(msgLength);
579         data.layout.rspLength = static_cast<uint16_t>(rspLength);
580         return data.value;
581     }
582 
getFuncId() const583     SFID      getFuncId() const {return sfid;}
584 
getFuncCtrl() const585     uint32_t getFuncCtrl() const {
586         return desc.layout.funcCtrl;
587     }
588 
589     ////////////////////////////////////////////////////////////////////////
590     // LSC-related operations
isLscOp() const591     bool isLscOp() const {return isLscDescriptor;}
getLscOp() const592     LSC_OP getLscOp() const {
593         assert(isLscOp());
594         return static_cast<LSC_OP>(desc.value & 0x3F);
595     }
596     LSC_ADDR_TYPE getLscAddrType() const;
597     int getLscAddrSizeBytes() const; // e.g. a64 => 8
598     LSC_DATA_ORDER getLscDataOrder() const;
599 
isEOTInst() const600     bool isEOTInst() const { return eotAfterMessage; }
601     void setEOT();
602 
603     // query methods common for all raw sends
604     uint16_t ResponseLength() const;
MessageLength() const605     uint16_t MessageLength() const { return desc.layout.msgLength; }
extMessageLength() const606     uint16_t extMessageLength() const { return (uint16_t)src1Len; }
isDataPortRead() const607     bool isDataPortRead() const { return accessType != SendAccess::WRITE_ONLY; }
isDataPortWrite() const608     bool isDataPortWrite() const { return accessType != SendAccess::READ_ONLY; }
getAccess() const609     SendAccess getAccess() const { return accessType; }
isValidFuncCtrl() const610     bool isValidFuncCtrl() const { return funcCtrlValid; }
611     bool isHeaderPresent() const;
612     void setHeaderPresent(bool val);
613 
614     ///////////////////////////////////////////////////////////////////////
615     // for HDC messages only (DC0/DC1/DC2/DP_DCRO(aka DP_CC))
616     //
617 
618     //////////////////////////////////////
619     // calling these functions on non-HDC may assert
getExtFuncCtrl() const620     uint16_t getExtFuncCtrl() const {
621         MUST_BE_TRUE(isHDC(), "getExtFuncCtrl on non-HDC message");
622         return extDesc.layout.extFuncCtrl;
623     }
624     uint32_t getHdcMessageType() const;
625     bool isAtomicMessage() const;
626     uint16_t getHdcAtomicOp() const;
627 
628     bool isSLMMessage() const;
629     unsigned getEnabledChannelNum() const;
630     unsigned getBlockNum() const;
631     unsigned getBlockSize() const;
632     bool isOwordLoad() const;
633     // OW1H ==> implies 2 (but shouldn't be used)
634     // asserts isOwordLoad()
635     unsigned getOwordsAccessed() const;
636 
637     bool isHdcTypedSurfaceWrite() const;
638 
639     // return offset in unit of HWords
getScratchRWOffset() const640     uint16_t getScratchRWOffset() const
641     {
642         MUST_BE_TRUE(isScratchRW(), "Message is not scratch space R/W.");
643         return (getFuncCtrl() & 0xFFFu);
644     }
645 
isScratchRW() const646     bool isScratchRW() const
647     {
648         // legacy DC0 scratch msg: bit[18] = 1
649         return getSFID() == SFID::DP_DC0 && ((getFuncCtrl() & 0x40000u) != 0);
650     }
isScratchRead() const651     bool isScratchRead() const
652     {
653         return isScratchRW() && (getFuncCtrl() & 0x20000u) == 0;
654     }
isScratchWrite() const655     bool isScratchWrite() const
656     {
657         return isScratchRW() && (getFuncCtrl() & 0x20000u) != 0;
658     }
659     // in terms of HWords (1, 2, 4, or 8)
getScratchRWSize() const660     uint16_t getScratchRWSize() const
661     {
662         MUST_BE_TRUE(isScratchRW(), "Message is not scratch space R/W.");
663         uint16_t bitV = ((getFuncCtrl() & 0x3000u) >> 12);
664         return  0x1 << bitV;
665     }
666     bool isByteScatterRW() const;
667     bool isDWScatterRW() const;
668     bool isQWScatterRW() const;
669     bool isUntypedRW() const;
670 
671     bool isA64Message() const;
672 
673     // for sampler mesasges only
isSampler() const674     bool isSampler() const { return getFuncId() == SFID::SAMPLER; }
isCPSEnabled() const675     bool isCPSEnabled() const { return extDesc.layout.cps != 0; }
676     uint32_t getSamplerMessageType() const;
677     bool is16BitInput() const;
678     bool is16BitReturn() const;
679 
isThreadMessage() const680     bool isThreadMessage() const {
681         return getSFID() == SFID::GATEWAY || getSFID() == SFID::SPAWNER;
682     }
683 
684 
isLSCTyped() const685     bool isLSCTyped() const {return isTyped() && isLSC();}
686     // atomic write or explicit barrier
isBarrierOrAtomic() const687     bool isBarrierOrAtomic() const {
688         return isAtomicMessage() || isBarrier();
689     }
690 
getBti() const691     const G4_Operand *getBti() const {return m_bti;}
getBti()692     G4_Operand *getBti()       {return m_bti;}
getSti() const693     const G4_Operand *getSti() const {return m_sti;}
getSti()694     G4_Operand *getSti()       {return m_sti;}
695 
696     // In rare cases we must update the surface pointer
697     // The send instructions also keeps a copy of the ExDesc parameter
698     // as a proper source operand (e.g. for dataflow algorithms).
699     // When they update their copy, they need to do the same for us.
setSurface(G4_Operand * newSurf)700     void setSurface(G4_Operand *newSurf) {m_bti = newSurf;}
701 
getDesc() const702     uint32_t getDesc() const { return desc.value; }
getExtendedDesc() const703     uint32_t getExtendedDesc() const { return extDesc.value; }
704 
705     std::string getDescription() const override;
706 private:
707     void setBindingTableIdx(unsigned idx);
708 
709 public:
710     ///////////////////////////////////////////////////////////////////////////
711     // for the generic interface
712     virtual size_t getSrc0LenBytes() const override;
713     virtual size_t getDstLenBytes() const override;
714     virtual size_t getSrc1LenBytes() const override;
715     //
getAccessType() const716     virtual SendAccess getAccessType() const override {return accessType;}
717     virtual std::pair<Caching,Caching> getCaching() const override;
718     virtual void setCaching(Caching l1, Caching l3) override;
719     //
720     virtual int getOffset() const override;
getSurface() const721     virtual G4_Operand *getSurface() const override {return m_bti;}
722     //
isEOT() const723     virtual bool isEOT() const override {return isEOTInst();}
isSLM() const724     virtual bool isSLM() const override {return isSLMMessage();}
isAtomic() const725     virtual bool isAtomic() const override {return isAtomicMessage();}
726     virtual bool isBarrier() const override;
727     virtual bool isFence() const override;
isScratch() const728     virtual bool isScratch() const override {return isScratchRW();}
729     virtual bool isTyped() const override;
730     //
731 }; // G4_SendDescRaw
732 
733 } // vISA::
734 
735 #endif // G4_SEND_DESCS_HPP
736