1 /*========================== begin_copyright_notice ============================
2 
3 Copyright (C) 2018-2021 Intel Corporation
4 
5 SPDX-License-Identifier: MIT
6 
7 ============================= end_copyright_notice ===========================*/
8 
9 #ifndef IGA_NATIVE_INSTDECODER_HPP
10 #define IGA_NATIVE_INSTDECODER_HPP
11 
12 #include "../../Frontend/IRToString.hpp"
13 #include "../../Frontend/Floats.hpp"
14 #include "../../IR/InstBuilder.hpp"
15 #include "../../strings.hpp"
16 #include "../BitProcessor.hpp"
17 #include "Field.hpp"
18 #include "Interface.hpp"
19 #include "MInst.hpp"
20 
21 #include <algorithm>
22 #include <functional>
23 #include <initializer_list>
24 #include <iomanip>
25 #include <sstream>
26 #include <string>
27 #include <vector>
28 
29 namespace iga
30 {
31     typedef std::function<void(uint64_t bits, std::stringstream &ss)> FormatFunction;
32 
nextPowerOfTwo(int v)33     static inline int nextPowerOfTwo(int v) {
34         v--;
35         v |= v >> 1;
36         v |= v >> 2;
37         v |= v >> 4;
38         v |= v >> 8;
39         v |= v >> 16;
40         v++;
41         return v;
42     }
decodePredCtrl(uint64_t bits)43     static inline PredCtrl decodePredCtrl(uint64_t bits) {
44         return static_cast<PredCtrl>(bits);
45     }
decodePredCtrlPvc(uint64_t bits)46     static inline PredCtrl decodePredCtrlPvc(uint64_t bits) {
47         switch (bits) {
48         case 0: return PredCtrl::NONE;
49         case 1: return PredCtrl::SEQ;
50         case 2: return PredCtrl::ANY;
51         case 3: return PredCtrl::ALL;
52         }
53         return static_cast<PredCtrl>(bits);
54     }
decodeExecSizeBits(uint64_t val)55     static inline ExecSize decodeExecSizeBits(uint64_t val) {
56         switch (val) {
57         case 0: return ExecSize::SIMD1;
58         case 1: return ExecSize::SIMD2;
59         case 2: return ExecSize::SIMD4;
60         case 3: return ExecSize::SIMD8;
61         case 4: return ExecSize::SIMD16;
62         case 5: return ExecSize::SIMD32;
63         default: return ExecSize::INVALID;
64         }
65     }
decodeChannelOffsetBits(uint64_t val)66     static inline ChannelOffset decodeChannelOffsetBits(uint64_t val) {
67         return static_cast<ChannelOffset>(val);
68     }
decodeFlagModifierBits(uint64_t val)69     static inline FlagModifier decodeFlagModifierBits(uint64_t val) {
70         FlagModifier fm;
71         switch (val) {
72         case 0: fm = FlagModifier::NONE; break;
73         case 1: fm = FlagModifier::EQ; break;
74         case 2: fm = FlagModifier::NE; break;
75         case 3: fm = FlagModifier::GT; break;
76         case 4: fm = FlagModifier::GE; break;
77         case 5: fm = FlagModifier::LT; break;
78         case 6: fm = FlagModifier::LE; break;
79         // case 7: reserved
80         case 8: fm = FlagModifier::OV; break;
81         case 9: fm = FlagModifier::UN; break;
82         default: fm = static_cast<FlagModifier>(val); break;
83         }
84         return fm;
85     }
decodeSrcModifierBits(uint64_t bits)86     static inline SrcModifier decodeSrcModifierBits(uint64_t bits)
87     {
88         switch (bits) {
89         case 0: return SrcModifier::NONE;
90         case 1: return SrcModifier::ABS;
91         case 2: return SrcModifier::NEG;
92         case 3: return SrcModifier::NEG_ABS;
93         default: return static_cast<SrcModifier>(bits);
94         }
95     }
decodeFlagModifier(uint64_t bits)96     static inline FlagModifier decodeFlagModifier(uint64_t bits)
97     {
98         switch (bits) {
99         case 0: return FlagModifier::NONE;
100         case 1: return FlagModifier::EQ;
101         case 2: return FlagModifier::NE;
102         case 3: return FlagModifier::GT;
103         case 4: return FlagModifier::GE;
104         case 5: return FlagModifier::LT;
105         case 6: return FlagModifier::LE;
106         //
107         case 8: return FlagModifier::OV;
108         case 9: return FlagModifier::UN;
109         default: return static_cast<FlagModifier>(bits);
110         }
111      }
112 
113     //
114     // This is a generic template for instruction decoders for various GEN
115     // platforms.  Users can use this via inheritance or composition equally.
116     // This class also decodes field by field for various debugging routines.
117     // E.g. iga64 -Xifs ... decodes each field
118     //
119     // The naming convention is as follows:
120     //
121     //  T  decodeXXXX(Field fXXXX)
122     // decodes something (an XXXX) using field fXXXX and store this into the
123     // field list.  This implies that fXXXX is properly part of the format and
124     // thus will not overlap with any other field decoded.  It also might
125     // commit the field to the instruction builder.
126     //
127     //  T  peekXXXX(Field fXXXX)
128     // decoes something, but quietly (don't add it to the list of
129     // fields decoded).  E.g. we might speculatively need to look at a field
130     // that we might not want to add.
131     //
132     // TODO: template<typename P> where P is PlatformInfo
133     //       for GEN-specific stuff use this var; e.g. P.decodeBasicRegType(...)
134     struct InstDecoder
135     {
136         InstBuilder              &builder;
137         ErrorHandler             &errorHandler;
138         const Model              &model;
139         const OpSpec             &os;
140         MInst                     bits;
141         FragmentList             *fields;
142         Loc                       loc;
143 
144         // instruction state
145         ExecSize                  execSize;
146         InstOptSet                instOptSet;
147 
InstDecoderiga::InstDecoder148         InstDecoder(
149             InstBuilder &_builder,
150             ErrorHandler &_errorHandler,
151             const Model &_model,
152             const OpSpec &_os,
153             MInst _bits,
154             FragmentList *_fields,
155             Loc _loc)
156             : builder(_builder)
157             , errorHandler(_errorHandler)
158             , model(_model)
159             , os(_os)
160             , bits(_bits)
161             , fields(_fields)
162             , loc(_loc)
163             , execSize(ExecSize::INVALID)
164             , instOptSet(0)
165         {
166         }
167 
isXeHpcPlusiga::InstDecoder168         bool isXeHpcPlus() const {
169             return model.platform >= Platform::XE_HPC;
170         }
171 
reportErroriga::InstDecoder172         void reportError(const char *msg) {
173             errorHandler.reportError(loc, msg);
174         }
reportErroriga::InstDecoder175         void reportError(const std::string &msg) {
176             errorHandler.reportError(loc, msg);
177         }
reportWarningiga::InstDecoder178         void reportWarning(const std::string &msg) {
179             errorHandler.reportWarning(loc, msg);
180         }
reportFieldErroriga::InstDecoder181         void reportFieldError(const Field &f, const char *msg) {
182             std::stringstream ss;
183             ss << f.name << ": " <<  msg;
184             reportError(ss.str());
185         }
reportFieldWarningiga::InstDecoder186         void reportFieldWarning(const Field &f, const char *msg) {
187             std::stringstream ss;
188             ss << f.name << ": " <<  msg;
189             reportWarning(ss.str());
190         }
reportFieldErrorInvalidValueiga::InstDecoder191         void reportFieldErrorInvalidValue(const Field &f) {
192             std::stringstream ss;
193             reportFieldError(f, "invalid value");
194         }
195 
196         ///////////////////////////////////////////
197         // PRIMITIVE FIELD ADDERS
addDecodedFieldiga::InstDecoder198         void addDecodedField(const Field &f, std::string meaning) {
199             if (fields) {
200                 int encodedFragments = 0;
201                 for (const Fragment &fr : f.fragments) {
202                     if (fr.isInvalid())
203                         break;
204                     else if (fr.isEncoded())
205                         encodedFragments++;
206                 }
207                 bool multipleFragments = false;
208                 int fragIx = 0;
209                 for (const Fragment &fr : f.fragments) {
210                     if (fr.isInvalid())
211                         break;
212                     else if (fr.isEncoded()) {
213                         std::string fragMeaning;
214                         if (multipleFragments) {
215                             std::stringstream ss;
216                             ss << "[frag. " << fragIx << "]: " << meaning;
217                             fragMeaning = ss.str();
218                             fragIx++;
219                         } else {
220                             fragMeaning = meaning;
221                         }
222                         addDecodedFragment(fr, fragMeaning);
223                     }
224                 }
225             }
226         }
addDecodedFragmentiga::InstDecoder227         void addDecodedFragment(const Fragment &fr, std::string val) {
228             if (fields)
229                 fields->emplace_back(fr, val);
230         }
decodeFragmentiga::InstDecoder231         uint64_t decodeFragment(const Fragment &f) {
232             addDecodedFragment(f, "");
233             return bits.getFragment(f);
234         }
decodeFragmentiga::InstDecoder235         uint64_t decodeFragment(const Fragment &f, FormatFunction fmt) {
236             auto val = bits.getFragment(f);
237             if (fields) {
238                 std::stringstream ss;
239                 fmt(val, ss);
240                 addDecodedFragment(f, ss.str());
241             }
242             return val;
243         }
decodeFieldWithFunctioniga::InstDecoder244         uint64_t decodeFieldWithFunction(
245             const Fragment &f, FormatFunction fmt)
246         {
247             return decodeFragment(f, fmt);
248         }
249 
250 
addReservediga::InstDecoder251         void addReserved(int off, int len, std::string errStr = "?") {
252             Fragment fRSVD("Reserved", off, len);
253             auto b = bits.getFragment(fRSVD);
254             addDecodedFragment(fRSVD, b != 0 ? errStr : "");
255         }
addReservediga::InstDecoder256         void addReserved(const Fragment &f) {
257             std::stringstream ss;
258             ss << "? (shadows " << f.name << ")";
259             addReserved(f.offset, f.length, ss.str().c_str());
260         }
addReservediga::InstDecoder261         void addReserved(const Field &f) {
262             for (const Fragment &fr : f.fragments) {
263                 if (fr.isEncoded()) {
264                     addReserved(fr);
265                 }
266             }
267         }
268 
decodeFieldU32iga::InstDecoder269         uint32_t decodeFieldU32(const Field &f) {
270             addDecodedField(f, "");
271             return (uint32_t)bits.getField(f);
272         }
273 
274         ///////////////////////////////////////////////////////////////////////////
275         // one bit fields
276         ///////////////////////////////////////////////////////////////////////////
277         template <typename T>
decodeFieldiga::InstDecoder278         T decodeField(
279             const Field &f,
280             T val0, const char *str0,
281             T val1, const char *str1)
282         {
283             IGA_ASSERT(f.length() == 1, "field is >1 bit");
284             T val;
285             const char *str = "";
286             auto b = bits.getField(f);
287             switch (b) {
288             case 0: val = val0; str = str0; break;
289             case 1: val = val1; str = str1; break;
290             default:
291                 val = val0; // for compiler warning
292                 IGA_ASSERT_FALSE("Unreachable");
293                 break; // unreachable
294             };
295             if (fields) {
296                 fields->emplace_back(f, str);
297             }
298             return val;
299         }
decodeBoolFieldiga::InstDecoder300         bool decodeBoolField(
301             const Field &f,
302             const char *falseMeaning,
303             const char *trueMeaning)
304         {
305             return decodeField<bool>(
306                 f, false, falseMeaning, true, trueMeaning);
307         }
308 
309         ///////////////////////////////////////////////////////////////////////
310         // two bit fields
311         ///////////////////////////////////////////////////////////////////////
312         template <typename T>
decodeFieldiga::InstDecoder313         T decodeField(
314             const Field &f,
315             T val0, const char *str0,
316             T val1, const char *str1,
317             T val2, const char *str2,
318             T val3, const char *str3)
319         {
320             // IGA_ASSERT(f.length == 2, "field is not a two bits");
321             // we can have subset fields like Dst.RgnHz[0] in ternary
322             IGA_ASSERT(f.length() <= 2, "field is <=2 bits");
323             T val;
324             const char *str = "";
325             auto b = bits.getField(f);
326             switch (b) {
327             case 0: val = val0; str = str0; break;
328             case 1: val = val1; str = str1; break;
329             case 2: val = val2; str = str2; break;
330             case 3: val = val3; str = str3; break;
331             default:
332                 val = val0; // for compiler warning
333                 IGA_ASSERT_FALSE("Unreachable");
334                 break; // unreachable
335             };
336             if (fields) {
337                 fields->emplace_back(f, str);
338             }
339             return val;
340         }
341 
342         ///////////////////////////////////////////////////////////////////////
343         // multi bit fields
344         ///////////////////////////////////////////////////////////////////////
decodeFieldiga::InstDecoder345         uint64_t decodeField(
346             const Field &f,
347             FormatFunction fmt)
348         {
349             auto val = bits.getField(f);
350             if (fields)
351             {
352                 std::stringstream ss;
353                 fmt(val, ss);
354                 fields->emplace_back(f, ss.str());
355             }
356             return val;
357         }
358 
359         template <typename T>
decodeFieldiga::InstDecoder360         T decodeField(
361             const Field &f,
362             T invalid,
363             std::initializer_list<std::pair<T,const char *>> vals)
364         {
365             IGA_ASSERT(nextPowerOfTwo((int)vals.size()) != f.length(),
366                 "field is wrong number of bits");
367             int i = 0;
368             T retVal = invalid;
369             const char *strVal = "?";
370             auto b = bits.getField(f);
371             for (const auto &val : vals) {
372                 if (i == (int)b) {
373                     retVal = val.first;
374                     strVal = val.second;
375                     break;
376                 }
377                 i++;
378             }
379             if (i == (int)vals.size() || retVal == invalid) { // didn't find it
380                 retVal = invalid;
381                 strVal = "?";
382                 reportFieldErrorInvalidValue(f);
383             }
384 
385             if (fields) {
386                 fields->emplace_back(f, strVal);
387             }
388             return retVal;
389         }
390 
391 
392         ///////////////////////////////////////////////////////////////////////
393         // generic GEN helpers
394         ///////////////////////////////////////////////////////////////////////
isMacroiga::InstDecoder395         bool isMacro() const {
396             return builder.isMacroOp();
397         }
398 
decodeMaskCtrliga::InstDecoder399         void decodeMaskCtrl(const Field &fMASKCTRL) {
400             if (decodeBoolField(fMASKCTRL, "", "WrEn")) {
401                 builder.InstNoMask(loc);
402             }
403         }
404 
decodePredicationiga::InstDecoder405         void decodePredication(
406             const Field &fPREDINV,
407             const Field &fPREDCTRL,
408             const Field &fFLAGREG)
409         {
410             PredCtrl predCtrl =
411                 isXeHpcPlus() ?
412                     decodePredCtrlPvc(bits.getField(fPREDCTRL)) :
413                     decodePredCtrl(bits.getField(fPREDCTRL));
414             addDecodedField(fPREDCTRL, ToSyntax(predCtrl));
415             bool predInv = decodeBoolField(fPREDINV, "", "~");
416             if (predInv && predCtrl == PredCtrl::NONE) {
417                 reportFieldError(fPREDINV,
418                     "PredCtrl is not set, but PredInv is set");
419             }
420             if (predCtrl != PredCtrl::NONE) {
421                 RegRef flagReg = peekFlagRegRef(fFLAGREG);
422                 builder.InstPredication(loc, predInv, flagReg, predCtrl);
423             }
424         }
425 
decodeBrCtliga::InstDecoder426         void decodeBrCtl(const Field &fBRCTL) {
427             bool brCtl = decodeBoolField(fBRCTL, "", ".b");
428             builder.InstSubfunction(
429                 brCtl ? BranchCntrl::ON : BranchCntrl::OFF);
430         }
431 
peekFlagRegRefiga::InstDecoder432         RegRef peekFlagRegRef(const Field &fFLAGREG) const {
433             auto val = (uint32_t)bits.getField(fFLAGREG);
434             return RegRef(val >> 1, val & 0x1);
435         }
436 
decodeFlagRegiga::InstDecoder437         RegRef decodeFlagReg(const Field &fFLAGREG) {
438             // flag register
439             decodeField(fFLAGREG,
440                 [] (uint64_t bits, std::stringstream &ss) {
441                     ss << "f" << (bits >> 1) << "." << (bits & 0x1);
442                 });
443             return peekFlagRegRef(fFLAGREG);
444         }
445 
decodeFlagModifierFieldiga::InstDecoder446         void decodeFlagModifierField(
447             const Field &fFLAGMOD,
448             const Field &fFLAGREG)
449         {
450             RegRef flagReg = peekFlagRegRef(fFLAGREG);
451             FlagModifier invalidModifier = static_cast<FlagModifier>(-1);
452             FlagModifier zeroValue = FlagModifier::NONE;
453             const char *zeroString = "";
454             if (os.is(Op::MATH) && isMacro()) {
455                 zeroValue = FlagModifier::EO;
456                 zeroString = "(eo) (early out)";
457             }
458             // TODO: use decodeFlagModifier() and ToSyntax
459             FlagModifier flagMod = decodeField<FlagModifier>(
460                 fFLAGMOD, invalidModifier, {
461                  {zeroValue, zeroString},
462                  {FlagModifier::EQ, "(eq)"},
463                  {FlagModifier::NE, "(ne)"},
464                  {FlagModifier::GT, "(gt)"},
465                  {FlagModifier::GE, "(ge)"},
466                  {FlagModifier::LT, "(lt)"},
467                  {FlagModifier::LE, "(le)"},
468                  {invalidModifier, "?"},
469                  {FlagModifier::OV, "(ov) (overflow)"},
470                  {FlagModifier::UN, "(un) (unordered)"}});
471             builder.InstFlagModifier(flagReg, flagMod);
472         }
473 
decodeImm32iga::InstDecoder474         ImmVal decodeImm32(const Field &fIMM32L, Type t) {
475             std::stringstream ss;
476             ImmVal immVal;
477             uint64_t val = bits.getField(fIMM32L);
478             //
479             // TODO: determine if ImmVal should store everything as s64
480             // otherwise I need to normalize what the GED parser and decoder
481             // a specific exmaple:
482             //  NATIVE:       0x0000000000008000
483             //  GED:          0xFFFFFFFFFFFF8000
484             //
485             // NATIVE: src0: PC[0]:
486             //   mov:        61 00 03 00 a0 45 05 01  00 00 00 00 00 80 00 80
487             //   mov (8|M0)               r1.0<1>:f     -32768:w
488             // GED takes a 64b value
489             switch (t) {
490             case Type::UW:
491                 immVal = (uint16_t)val;
492                 ss << std::hex << (uint16_t)val;
493                 break;
494             case Type::UD:
495                 immVal = (uint32_t)val;
496                 ss << std::hex << "0x" << (uint32_t)val;
497                 break;
498             case Type::W:
499                 immVal = (int16_t)val;
500                 immVal.s64 = immVal.s16;
501                 ss << std::dec << (int16_t)val;
502                 break;
503             case Type::D:
504                 immVal = (int32_t)val;
505                 immVal.s64 = immVal.s32;
506                 ss << std::dec << (int32_t)val;
507                 break;
508             case Type::HF:
509                 immVal = (uint16_t)val;
510                 immVal.kind = ImmVal::Kind::F16;
511                 FormatFloat(ss, FloatFromBits((uint16_t)val));
512                 break;
513             case Type::F:
514                 immVal = FloatFromBits((uint32_t)val);
515                 FormatFloat(ss, FloatFromBits((uint32_t)val));
516                 break;
517             case Type::V:
518             case Type::UV:
519                 immVal = (uint32_t)val;
520                 ss << "(";
521                 for (int i = 7; i >= 0; i--) {
522                     if (i < 7) ss << ',';
523                     if (t == Type::V) {
524                         ss << std::hex << getSignedBits<int64_t>((int64_t)val, i*4, 4);
525                     } else {
526                         ss << std::dec << getBits<uint64_t>(val, i*4, 4);
527                     }
528                 }
529                 ss << ")";
530                 break;
531             case Type::VF:
532                 immVal = (uint32_t)val;
533                 ss << "(";
534                 for (int i = 3; i >= 0; i--) {
535                     if (i < 3) ss << ',';
536                     FormatFloat(ss, (uint8_t)getBits(val, i*8, 8));
537                 }
538                 ss << ")";
539                 break;
540                 break;
541             default:
542                 immVal = (uint32_t)0;
543                 reportFieldError(fIMM32L, "invalid type for 32b IMM");
544                 ss << "?";
545             }
546 
547             addDecodedField(fIMM32L, ss.str());
548 
549             return immVal;
550         }
551 
decodeImm64iga::InstDecoder552         ImmVal decodeImm64(
553             const Field &fIMM32L, const Field &fIMM32H, Type type)
554         {
555             uint64_t lo = bits.getField(fIMM32L);
556             uint64_t hi = bits.getField(fIMM32H);
557             ImmVal immVal;
558             immVal.u64 = ((hi << 32) | lo);;
559             std::stringstream ss;
560             ss << "(";
561             switch (type) {
562             case Type::DF:
563                 immVal.kind = ImmVal::Kind::F64;
564                 FormatFloat(ss, FloatFromBits(immVal.u64));
565                 break;
566             case Type::UQ:
567                 immVal.kind = ImmVal::Kind::U64;
568                 ss << immVal.u64;
569                 break;
570             case Type::Q:
571                 immVal.kind = ImmVal::Kind::S64;
572                 ss << immVal.s64;
573                 break;
574             default:
575                 ss << "ERROR: expected 64b type";
576                 reportError("ERROR: expected 64b type");
577             }
578             ss << ")";
579             addDecodedField(fIMM32L, "LO32" + ss.str());
580             addDecodedField(fIMM32H, "HI32" + ss.str());
581             return immVal;
582         }
583 
decodeExecOffsetInfoiga::InstDecoder584         void decodeExecOffsetInfo(
585             const Field &fEXECSIZE,
586             const Field &fCHANOFF)
587         {
588             execSize = decodeExecSizeBits(bits.getField(fEXECSIZE));
589             if (execSize == ExecSize::INVALID) {
590                 reportFieldErrorInvalidValue(fEXECSIZE);
591             }
592             std::stringstream ssEs;
593             ssEs << "(" << ToSyntax(execSize) << "|...)";
594             addDecodedField(fEXECSIZE, ssEs.str());
595 
596             auto chOffBits = bits.getField(fCHANOFF);
597             ChannelOffset chOff = decodeChannelOffsetBits(chOffBits);
598             if (chOff < ChannelOffset::M0 || chOff > ChannelOffset::M28) {
599                 reportFieldErrorInvalidValue(fCHANOFF);
600             }
601             std::stringstream ssCo;
602             ssCo << "(..." << ToSyntax(chOff) << ")";
603             addDecodedField(fCHANOFF, ssCo.str());
604 
605             builder.InstExecInfo(loc, execSize, loc, chOff);
606         }
607 
decodeDstModifieriga::InstDecoder608         DstModifier decodeDstModifier(const Field &fSATURATE) {
609             return
610                 decodeField(fSATURATE,
611                     DstModifier::NONE, "",
612                     DstModifier::SAT, "(sat)");
613         }
614 
decodeSrcModsiga::InstDecoder615         SrcModifier decodeSrcMods(const Field &fSRCMODS) {
616             return decodeField<SrcModifier>(
617                 fSRCMODS,
618                 SrcModifier::NONE,"",
619                 SrcModifier::ABS, "(abs)",
620                 SrcModifier::NEG, os.isBitwise() ? "~" : "-",
621                 SrcModifier::NEG_ABS,"-(abs)");
622         }
623 
decodeMathMacroRegiga::InstDecoder624         MathMacroExt decodeMathMacroReg(const Field &fSPCACC) {
625             addReserved(fSPCACC.fragments[0].offset + 4, 1);
626             return decodeMathMacroRegField(fSPCACC);
627         }
628 
decodeSubRegiga::InstDecoder629         void decodeSubReg(
630             OperandInfo &opInfo,
631             const Field &fSUBREG)
632         {
633             decodeSubRegWithType(
634                 opInfo, fSUBREG, opInfo.type, ToSyntax(opInfo.type));
635         }
636 
637         // e.g. for subregisters without proper types
decodeSubRegWithImplicitTypeiga::InstDecoder638         void decodeSubRegWithImplicitType(
639             OperandInfo &opInfo,
640             const Field &fSUBREG,
641             Type t)
642         {
643             decodeSubRegWithType(opInfo, fSUBREG, t, "");
644         }
645 
decodeSubRegWithTypeiga::InstDecoder646         void decodeSubRegWithType(
647             OperandInfo &opInfo,
648             const Field &fSUBREG,
649             Type type,
650             std::string typeSyntax)
651         {
652             auto srb = (int)bits.getField(fSUBREG);
653             auto scaled = BinaryOffsetToSubReg(srb, opInfo.regOpName, type, model.platform);
654             auto unscaled =
655                 SubRegToBinaryOffset((int)scaled, opInfo.regOpName, type, model.platform);
656             if ((int)unscaled != srb) {
657                 reportFieldError(fSUBREG,
658                     "subregister offset is misaligned for type size");
659             }
660             bool scaleArfFc = false;
661             scaleArfFc = model.platform >= Platform::XE_HPC;
662             if (opInfo.regOpName == RegName::ARF_FC && scaleArfFc) {
663                 scaled /= 2;
664             }
665             opInfo.regOpReg.subRegNum = scaled;
666 
667             std::stringstream ss;
668             ss << "." << (int)opInfo.regOpReg.subRegNum << typeSyntax;
669             addDecodedField(fSUBREG, ss.str());
670         }
671 
decodeRegDirectFieldsiga::InstDecoder672         void decodeRegDirectFields(
673             OpIx opIndex,
674             OperandInfo &opInfo,
675             const Field &fREGFILE, // direct only
676             const Field &fSPCACC,
677             const Field &fSUBREG,
678             const Field &fREG)
679         {
680             decodeRegFields(opInfo, fREGFILE, fREG);
681             if (isMacro()) {
682                 opInfo.kind = Operand::Kind::MACRO;
683                 opInfo.regOpMathMacroExtReg = decodeMathMacroRegField(fSPCACC);
684                 addReserved(
685                     fSPCACC.fragments[0].offset + fSPCACC.fragments[0].length,
686                     1);
687                 if (!IsTernary(opIndex) &&
688                     (IsDst(opIndex) || ToSrcIndex(opIndex) == 0) &&
689                     fSUBREG.length() > 1 &&
690                     fSUBREG.fragments[0].length == 1)
691                 {
692                     // for binary macros, the low of subreg is stowed elsewhere
693                     addReserved(fSUBREG.fragments[0]);
694                 }
695             } else {
696                 opInfo.kind = Operand::Kind::DIRECT;
697                 decodeSubReg(opInfo, fSUBREG);
698             }
699         }
700 
decodeRegFieldsiga::InstDecoder701         void decodeRegFields(
702             OperandInfo &opInfo,
703             const Field &fREGFILE,
704             const Field &fREG)
705         {
706             bool isGrf = decodeBoolField(fREGFILE, "ARF", "GRF");
707             std::stringstream ss;
708             auto regVal = bits.getField(fREG);
709             if (isGrf) {
710                 opInfo.regOpName = RegName::GRF_R;
711                 opInfo.regOpReg.regNum = (uint16_t)regVal;
712                 ss << "r" << regVal;
713             } else {
714                 readArfRegisterInfo(opInfo, fREG, ss);
715             }
716             addDecodedField(fREG, ss.str());
717         }
718 
719         // factored out so decodeInstSendDstOperand can share it
readArfRegisterInfoiga::InstDecoder720         void readArfRegisterInfo(
721             OperandInfo &opInfo,
722             const Field &fREG,
723             std::stringstream &ssDesc)
724         {
725             auto regVal = bits.getField(fREG);
726             const RegInfo *regInfo =
727                 model.lookupArfRegInfoByRegNum((uint8_t)regVal);
728             if (regInfo == nullptr) {
729                 opInfo.regOpName = RegName::INVALID;
730                 ssDesc << "invalid ARF";
731                 std::stringstream ssErr;
732                 ssErr << "invalid ARF Reg (" << fmtHex(regVal, 2) << ")";
733                 reportFieldError(fREG, ssErr.str().c_str());
734                 return;
735             }
736             //
737             opInfo.regOpName = regInfo->regName;
738             ssDesc << regInfo->syntax;
739             int arfReg = 0;
740             if (regVal > 0xFF || !regInfo->decode((uint8_t)regVal, arfReg)) {
741                 ssDesc << arfReg << "?";
742                 std::stringstream ss;
743                 ss << regInfo->syntax << arfReg << " is out of bounds";
744                 reportFieldError(fREG, ss.str().c_str());
745             } else {
746                 if (regInfo->hasRegNum()) {
747                     ssDesc << arfReg;
748                 }
749                 opInfo.regOpReg.regNum = (uint16_t)arfReg;
750                 if (regInfo->regNumBase > 0) {
751                     // if the register covers to another, let's tell
752                     // them which
753                     uint8_t coverRegBits = (uint8_t)(regVal & 0xF0);
754                     const RegInfo *coverRegInfo =
755                         model.lookupArfRegInfoByRegNum(coverRegBits);
756                     if (coverRegInfo) {
757                         // e.g. XE+ acc10 is mme2
758                         ssDesc << " (" <<
759                             coverRegInfo->syntax << (regVal & 0xF) << ")";
760                     }
761                 }
762             }
763         }
764 
765 
decodeMathMacroRegFieldiga::InstDecoder766         MathMacroExt decodeMathMacroRegField(const Field &fSPCACC) {
767             return decodeField<MathMacroExt>(
768                 fSPCACC, MathMacroExt::INVALID,
769                 {{MathMacroExt::MME0,".mme0"},
770                  {MathMacroExt::MME1,".mme1"},
771                  {MathMacroExt::MME2,".mme2"},
772                  {MathMacroExt::MME3,".mme3"},
773                  {MathMacroExt::MME4,".mme4"},
774                  {MathMacroExt::MME5,".mme5"},
775                  {MathMacroExt::MME6,".mme6"},
776                  {MathMacroExt::MME7,".mme7"},
777                  {MathMacroExt::NOMME,".nomme"}});
778         }
779 
decodeInstOptiga::InstDecoder780         bool decodeInstOpt(const Field &fINSTOPT, InstOpt opt) {
781             IGA_ASSERT(fINSTOPT.length() == 1, "inst opt field is >1 bit");
782 
783             std::stringstream ss;
784             bool z = bits.getField(fINSTOPT) != 0;
785             if (z) {
786                 instOptSet.add(opt);
787                 ss << "{" << ToSyntax(opt) << "}";
788             }
789             addDecodedField(fINSTOPT, ss.str());
790             return z;
791         }
792     }; // InstDecoder
793 } // iga::
794 
795 
796 #endif // IGA_NATIVE_INSTDECODER_HPP
797