1 /*========================== begin_copyright_notice ============================
2 
3 Copyright (C) 2020-2021 Intel Corporation
4 
5 SPDX-License-Identifier: MIT
6 
7 ============================= end_copyright_notice ===========================*/
8 
9 #ifndef _IGA_BACKEND_MESSAGES_MESSAGEDECODER_HPP_
10 #define _IGA_BACKEND_MESSAGES_MESSAGEDECODER_HPP_
11 
12 #include "../../IR/Messages.hpp"
13 #include "../../Frontend/IRToString.hpp"
14 #include "../../asserts.hpp"
15 #include "../Native/Field.hpp"
16 #include "../../Models/Models.hpp"
17 
18 #include <algorithm>
19 #include <functional>
20 #include <sstream>
21 #include <tuple>
22 #include <vector>
23 
24 namespace iga {
25     using DescFieldFormatter =
26         std::function<void (std::stringstream &,uint32_t)>;
NO_DECODE(std::stringstream &,uint32_t)27     static inline void NO_DECODE(std::stringstream &,uint32_t) { }
28 
29 
30     struct MessageDecoder {
31         // inputs
32         const Model           &decodeModel;
33         const SFID             sfid;
34         ExecSize               instExecSize;
35         const SendDesc         desc, exDesc;
36 
37         // outputs
38         DecodeResult          &result;
39 
40         const int DEFAULT_EXEC_SIZE, BITS_PER_REGISTER;
41 
MessageDecoderiga::MessageDecoder42         MessageDecoder(
43             Platform _platform,
44             SFID _sfid,
45             ExecSize _instExecSize,
46             SendDesc _exDesc,
47             SendDesc _desc,
48             DecodeResult &_result)
49             : decodeModel(Model::LookupModelRef(_platform))
50             , sfid(_sfid)
51             , instExecSize(_instExecSize)
52             //
53             , desc(_desc)
54             , exDesc(_exDesc)
55             //
56             , result(_result)
57             //
58             , DEFAULT_EXEC_SIZE((_platform >= Platform::XE_HPC) ? 32 : 16)
59             , BITS_PER_REGISTER((_platform >= Platform::XE_HPC) ? 512 : 256)
60         {
61             result.info.op = SendOp::INVALID;
62             result.info.cachingL3 = result.info.cachingL1 = CacheOpt::DEFAULT;
63             result.info.elemSizeBitsRegFile = result.info.elemSizeBitsMemory = 0;
64             result.info.channelsEnabled = result.info.elemsPerAddr = 0;
65             result.info.execWidth =
66                 _instExecSize != ExecSize::INVALID ? int(_instExecSize) : 0;
67             result.info.attributeSet = MessageInfo::Attr::NONE;
68             result.info.addrType = AddrType::FLAT;
69             result.info.surfaceId = 0;
70             result.info.immediateOffset = 0;
71             result.info.docs = nullptr;
72             //
73             // syntax.sfid = _sfid;
74             result.syntax.controls = "." + ToSyntax(_sfid);
75             //
76             decodePayloadSizes();
77         }
78 
platformiga::MessageDecoder79         Platform platform() const {
80             return model().platform;
81         }
82 
modeliga::MessageDecoder83         const Model &model() const {
84             return decodeModel;
85         }
86 
platformInRangeiga::MessageDecoder87         bool platformInRange(Platform lo, Platform hi) const {
88             return platform() >= lo && platform() <= hi;
89         }
90 
setDociga::MessageDecoder91         void setDoc(const char *doc) {
92             setDoc(doc, doc, doc);
93         }
setDociga::MessageDecoder94         void setDoc(const char *preXe, const char *xe, const char *) {
95             result.info.docs = chooseDoc(preXe, xe, "?");
96         }
chooseDociga::MessageDecoder97         const char *chooseDoc(
98             const char *preXe, const char *xe, const char *) const
99         {
100             preXe = preXe ? preXe : "?";
101             xe = xe ? xe : "?";
102             return platform() < Platform::XE ? preXe : xe;
103         }
104 
105         /////////////////////////////////////////////////////////////
106         // diagnostics
107         template <
108             typename T1,
109             typename T2 = const char *,
110             typename T3 = const char *>
addDiagiga::MessageDecoder111         void addDiag(
112                 DiagnosticList &dl,
113                 int off, int len,
114                 T1 t1,
115                 T2 t2 = "",
116                 T3 t3 = "")
117         {
118             std::stringstream ss;
119             ss << t1 << t2 << t3;
120             dl.emplace_back(DescField(off,len), ss.str());
121         }
122         template <typename T1,
123             typename T2 = const char *, typename T3 = const char *>
warningiga::MessageDecoder124         void warning(int off, int len, T1 t1, T2 t2 = "", T3 t3 = "") {
125             addDiag(result.warnings, off, len, t1, t2, t3);
126         }
127         template <typename T1,
128             typename T2 = const char *, typename T3 = const char *>
erroriga::MessageDecoder129         void error(int off, int len, T1 t1, T2 t2 = "", T3 t3 = "") {
130             addDiag(result.errors, off, len, t1, t2, t3);
131         }
132 
133         // offset +32 to 64 fetch from exDesc
134         // peeks at a field without adding it
getDescBitsiga::MessageDecoder135         uint32_t getDescBits(int off, int len) const {
136             uint32_t bits = desc.imm;
137             if (off >= 32) {
138                 off -= 32;
139                 bits = exDesc.imm;
140             }
141             uint32_t mask = len == 32 ? 0xFFFFFFFF : ((1 << len) - 1);
142             return (int)((bits >> off) & mask);
143         }
144 
getDescBitiga::MessageDecoder145         uint32_t getDescBit(int off) const {
146             return getDescBits(off, 1) != 0;
147         }
148 
decodeExDescFieldiga::MessageDecoder149         uint32_t decodeExDescField(
150             const char *fieldName,
151             int off,
152             int len,
153             DescFieldFormatter fmtMeaning = NO_DECODE)
154         {
155             auto val = getDescBits(off + 32, len);
156             std::stringstream ss;
157             fmtMeaning(ss, val);
158             addField(fieldName, off + 32, len, val, ss.str());
159             return val;
160         }
decodeDescFieldiga::MessageDecoder161         uint32_t decodeDescField(
162             const char *fieldName,
163             int off,
164             int len,
165             DescFieldFormatter fmtMeaning = NO_DECODE)
166         {
167             auto val = getDescBits(off, len);
168             std::stringstream ss;
169             fmtMeaning(ss, val);
170             addField(fieldName, off, len, val, ss.str());
171             return val;
172         }
decodeDescBitFieldiga::MessageDecoder173         uint32_t decodeDescBitField(
174             const char *fieldName,
175             int off,
176             const char *zero,
177             const char *one)
178         {
179             return decodeDescField(fieldName, off, 1,
180                 [&] (std::stringstream &ss, uint32_t val) {
181                     ss << (val ? one : zero);
182                 });
183         }
decodeDescBitFieldiga::MessageDecoder184         uint32_t decodeDescBitField(
185             const char *fieldName,
186             int off,
187             const char *one)
188         {
189             return decodeDescBitField(fieldName, off, "", one);
190         }
191 
192         // normally use getDescBitsField, but in cases where you've already
193         // decoded, the meaning and just want to record the result
addFieldiga::MessageDecoder194         void addField(
195             const char *fieldName,
196             int off,
197             int len,
198             uint32_t val,
199             std::string meaning)
200         {
201             Fragment f(fieldName, off, len);
202             for (const auto &fvs : result.fields) {
203                 const auto &f1 = std::get<0>(fvs);
204                 if (f1.overlaps(f)) {
205                     // uncomment for debugging
206                     // std::stringstream ss;
207                     // ss << "overlapped fields: " << f1.name << " and " << f.name;
208                     // IGA_ASSERT_FALSE(ss.str().c_str());
209                     return; // replicated access (don't record again)
210                 }
211             }
212             result.fields.emplace_back(f, val, meaning);
213         }
214 
215         ///////////////////////////////////////////////////////////////////////////
216         // decoder helpers
decodeExpectediga::MessageDecoder217         bool decodeExpected(
218             int off,
219             int len,
220             const char *fieldName,
221             uint32_t expected)
222         {
223             auto val = getDescBits(off, len);
224             if (val != expected) {
225                 warning(off, len, "field should be ", expected);
226             }
227             addField(fieldName, off, len, val, "");
228             return val == expected;
229         }
230 
231         // decodes MLen, RLen, and XLen if present
232         // (Src0.Length, Dst.Length, Src1.Length)
233         void decodePayloadSizes();
234 
235         ///////////////////////////////////////////////////////////////////////////
236         // the most generic setter
setScatterGatherOpXiga::MessageDecoder237         void setScatterGatherOpX(
238             std::string msgSym,
239             std::string msgImpl,
240             SendOp op,
241             AddrType addrType,
242             SendDesc surfaceId,
243             CacheOpt l1,
244             CacheOpt l3,
245             int addrSize,
246             int bitsPerElemReg, int bitsPerElemMem,
247             int elemsPerAddr,
248             int simd,
249             MessageInfo::Attr extraAttrs = MessageInfo::Attr::NONE)
250         {
251             MessageInfo &mi = result.info;
252             mi.symbol = msgSym;
253             mi.description = msgImpl;
254             mi.op = op;
255             mi.cachingL1 = l1;
256             mi.cachingL3 = l3;
257             mi.addrType = addrType;
258             mi.surfaceId = surfaceId;
259             mi.attributeSet |= extraAttrs;
260             mi.addrSizeBits = addrSize;
261             mi.elemSizeBitsRegFile = bitsPerElemReg;
262             mi.elemSizeBitsMemory = bitsPerElemMem;
263             mi.elemsPerAddr = elemsPerAddr;
264             mi.channelsEnabled = 0;
265             mi.execWidth = simd;
266         }
267 
setScatterGatherOpiga::MessageDecoder268         void setScatterGatherOp(
269             std::string msgSym,
270             std::string msgDesc,
271             SendOp op,
272             AddrType addrType,
273             SendDesc surfaceId,
274             int addrSize,
275             int bitsPerElem,
276             int elemsPerAddr,
277             int simd,
278             MessageInfo::Attr extraAttrs = MessageInfo::Attr::NONE)
279         {
280             setScatterGatherOpX(
281                 msgSym,
282                 msgDesc,
283                 op,
284                 addrType,
285                 surfaceId,
286                 CacheOpt::DEFAULT,
287                 CacheOpt::DEFAULT,
288                 addrSize,
289                 bitsPerElem, bitsPerElem,
290                 elemsPerAddr,
291                 simd,
292                 extraAttrs);
293         }
294 
295         // for miscellaneous stuff such as fences and whatnot
296         //
297         // treat the payloads as full register units and set the op to SIMD1
setSpecialOpXiga::MessageDecoder298         void setSpecialOpX(
299             std::string msgSym,
300             std::string msgDesc,
301             SendOp op,
302             AddrType addrType,
303             SendDesc surfaceId,
304             int mlen,
305             int rlen,
306             MessageInfo::Attr extraAttrs = MessageInfo::Attr::NONE)
307         {
308             MessageInfo &mi = result.info;
309             mi.symbol = msgSym;
310             mi.description = msgDesc;
311             mi.op = op;
312             mi.cachingL1 = CacheOpt::DEFAULT;
313             mi.cachingL3 = CacheOpt::DEFAULT;
314             mi.addrType = addrType;
315             mi.surfaceId = surfaceId;
316             mi.addrSizeBits = mlen*BITS_PER_REGISTER;
317             // e.g. SIMD16 platforms are 256b (two full registers)
318             mi.elemSizeBitsRegFile = rlen*BITS_PER_REGISTER;
319             mi.elemSizeBitsMemory = mi.elemSizeBitsRegFile;
320             mi.channelsEnabled = 0;
321             mi.elemsPerAddr = 1;
322             mi.execWidth = 1;
323             mi.attributeSet = extraAttrs | MessageInfo::Attr::VALID;
324         }
325 
326         // shared by subclasses
327         void addLscFenceFields(
328             std::stringstream &sym, std::stringstream &desc);
329         void addLscFenceScopeField(
330             std::stringstream &sym, std::stringstream &desc);
331         void addLscFencePortFields(
332             std::stringstream &sym, std::stringstream &desc);
333     }; // MessageDecoder
334 
335 
336     ///////////////////////////////////////////////////////////////////////////
337     // shared by MessageDecoderHDC, MessageDecoderOther
338     struct MessageDecoderLegacy : MessageDecoder {
339         static const int SLM_BTI = 0xFE;
340         static const int COHERENT_BTI = 0xFF;
341         static const int NONCOHERENT_BTI = 0xFD;
MessageDecoderLegacyiga::MessageDecoderLegacy342         MessageDecoderLegacy(
343             Platform _platform,
344             SFID _sfid,
345             ExecSize _instExecSize,
346             SendDesc _exDesc,
347             SendDesc _desc,
348             DecodeResult &_result)
349             : MessageDecoder(
350                 _platform, _sfid, _instExecSize,
351                 _exDesc, _desc, _result)
352         {
353         }
354 
355         // from legacy encodings
decodeBTIiga::MessageDecoderLegacy356         int decodeBTI(int addrBits) {
357             int bti = (int)getDescBits(0, 8);
358             std::stringstream ss;
359             ss << "surface " << bti;
360             if (bti == SLM_BTI) {
361                 ss << " (SLM)";
362             } else if (bti == COHERENT_BTI) {
363                 if (addrBits == 64)
364                     ss << " A64 ";
365                 else
366                     ss << " A32 ";
367                 ss << " (coherent stateless)";
368             } else if (bti == NONCOHERENT_BTI) {
369                 if (addrBits == 64)
370                     ss << " A64";
371                 else
372                     ss << " A32";
373                 ss << " (incoherent stateless)";
374             } else if (bti == 0xFC) {
375                 ss << " (SSO)";
376             }
377             addField("BTI", 0, 8, bti, ss.str());
378             return bti;
379         }
380 
381         /////////////////////////////////////////////////////
382         // "header" decoding
decodeMDC_Higa::MessageDecoderLegacy383         bool decodeMDC_H() { // optional
384             return decodeDescBitField(
385                 "Header",
386                 19,
387                 "absent",
388                 "included") != 0;
389         }
decodeMDC_HFiga::MessageDecoderLegacy390         void decodeMDC_HF() {
391             if (getDescBit(19) != 0)
392                 warning(19, 1,
393                     "this message forbids a header (and it's included)");
394         }
decodeMDC_HRiga::MessageDecoderLegacy395         void decodeMDC_HR() {
396             if (!decodeMDC_H())
397                 warning(19, 1,
398                     "this message requires a header (and it's absent)");
399         }
decodeMDC_H2iga::MessageDecoderLegacy400         bool decodeMDC_H2() {
401             return decodeDescBitField(
402                 "DualHeader", 19, "absent",
403                 "included (two register header)") != 0;
404         }
405 
406         ///////////////////////////////////////////////////////////////////////
407         // some shared decoder helpers
decodeMDC_SM2iga::MessageDecoderLegacy408         int decodeMDC_SM2(int off) {
409             // yeah SM2 is really 1 bit (2 means two values)
410             int bits =
411                 decodeDescBitField("SimdMode:MDC_SM2", off, "SIMD8", "SIMD16");
412             return bits ? 16 : 8;
413         }
414     }; // MessageDecoderLegacy
415 
416     // see MessageDecoderHDC.cpp
417     void decodeDescriptorsHDC(
418         Platform platform, SFID sfid, ExecSize execSize,
419         SendDesc exDesc, SendDesc desc,
420         DecodeResult &result);
421 
422     // see MessageDecoderOther.cpp
423     void decodeDescriptorsOther(
424         Platform platform, SFID sfid, ExecSize execSize,
425         SendDesc exDesc, SendDesc desc,
426         DecodeResult &result);
427 
428     void decodeDescriptorsLSC(
429         Platform platform, SFID sfid, ExecSize execSize,
430         SendDesc exDesc, SendDesc desc,
431         DecodeResult &result);
432 
433     bool encodeDescriptorsLSC(
434         Platform p,
435         const VectorMessageArgs &vma,
436         SendDesc &exDesc,
437         SendDesc &desc,
438         std::string &err);
439 
440 } // iga::
441 
442 #endif // _IGA_BACKEND_MESSAGES_MESSAGEDECODER_HPP_
443