1 /*========================== begin_copyright_notice ============================
2 
3 Copyright (C) 2017-2021 Intel Corporation
4 
5 SPDX-License-Identifier: MIT
6 
7 ============================= end_copyright_notice ===========================*/
8 
9 #ifndef IGA_BACKEND_NATIVE_INSTENCODER_HPP
10 #define IGA_BACKEND_NATIVE_INSTENCODER_HPP
11 
12 #include "MInst.hpp"
13 #include "Field.hpp"
14 #include "../BitProcessor.hpp"
15 #include "../EncoderOpts.hpp"
16 #include "../../IR/Kernel.hpp"
17 #include "../../asserts.hpp"
18 #include "../../bits.hpp"
19 #include "../../strings.hpp"
20 //
21 #include <cstdint>
22 #include <functional>
23 #include <sstream>
24 #include <string>
25 #include <vector>
26 //
27 #ifdef _DEBUG
28 // IGA_IGA_VALIDATE_BITS adds extra structures and code to ensure that each bit
29 // the instruction encoded gets written at most once.  This can catch
30 // accidental field overlaps quite effectively.
31 //
32 // The neceessary assumption follows that encoders must not get lazy or sloppy
33 // and just clobber bits.  Set it once only.
34 #define IGA_VALIDATE_BITS
35 #endif
36 
37 
38 namespace iga
39 {
40     // immLo <= offset < immHi
rangeContains(int immLo,int immHi,int offset)41     static inline bool rangeContains(int immLo, int immHi, int offset) {
42         return immLo <= offset && offset < immHi;
43     }
44 
45     struct InstEncoderState
46     {
47         int                            instIndex = 0;
48         const Instruction*             inst = nullptr;
49 #ifdef IGA_VALIDATE_BITS
50         // All the bit fields set by some field during this instruction encoding
51         // e.g. if a field with bits [127:96] is set to 00000000....0001b
52         // this bit mask will contain 1111....111b's for that field
53         // This allows us to detect writing to two overlapped fields, which
54         // indicates an internal logical error in the encoder.
55         MInst                          dirty;
56         // This contains a list of all the fields we set during an instruction
57         // encoding so we can run through the list and determine which fields
58         // overlapped.
59         std::vector<const Fragment *>    fragmentsSet;
60 #endif
InstEncoderStateiga::InstEncoderState61         InstEncoderState(
62               int _instIndex
63             , const Instruction *_inst
64 #ifdef IGA_VALIDATE_BITS
65             , const MInst &_dirty
66             , const std::vector<const Fragment*> &_fieldsSet
67 #endif
68             )
69             : instIndex(_instIndex)
70             , inst(_inst)
71 #ifdef IGA_VALIDATE_BITS
72             , dirty(_dirty)
73             , fragmentsSet(_fieldsSet)
74 #endif
75         {
76         }
InstEncoderStateiga::InstEncoderState77         InstEncoderState() { }
78     };
79 
80     struct Backpatch
81     {
82         InstEncoderState               state;
83         const Block                   *target;
84         const Field                   &fragment;
85         enum Type {REL, ABS}           type;
86 
Backpatchiga::Backpatch87         Backpatch(
88             InstEncoderState &_state,
89             const Block *_target,
90             const Field &_field,
91             Type _type = REL)
92             : state(_state)
93             , target(_target)
94             , fragment(_field)
95             , type(_type) { }
96         // TODO: determine where copy construction used to eliminate
97         // Backpatch(const Backpatch&) = delete;
98     };
99     typedef std::vector<Backpatch> BackpatchList;
100 
101     // can be passed into the encoding if we want to know the result
102     struct CompactionDebugInfo {
103         std::vector<Op>                        fieldOps; // the op we were trying to compact
104         std::vector<const CompactionMapping *> fieldMisses; // which indices missed
105         std::vector<uint64_t>                  fieldMapping; // what we tried to match (parallel)
106     };
107     enum class CompactionResult {
108         CR_SUCCESS,
109         CR_NO_COMPACT,     // {NoCompact} (or -Xnoautocompact and {}
110         CR_NO_FORMAT,      // e.g. send or jump
111         CR_NO_AUTOCOMPACT, // no annotation and {Compacted} not set
112         CR_MISS            // fragment misses
113     };
114 
115     //////////////////////////////////////////////////////////
116     // generic encoder for all platforms
117     // subclasses specialize the necessary functions
118     class InstEncoder : public BitProcessor
119     {
120         // the encoder options (e.g. for auto-compaction)
121         EncoderOpts                    opts;
122         //
123         // the platform we're encoding for
124         const Model                   &model;
125         //
126         // The target bits to encode to
127         MInst                         *bits = nullptr;
128         //
129         // A backpatch list that we can add to.  A parent encoder is permitted
130         // to copy or shadow this list.  Hence, this class may not assume the
131         // state is preserved between the calls of encodeInstruction and
132         // resolveBackpatch.
133         BackpatchList                  backpatches;
134         //
135         // state used by the encoder (can be saved for backpatches)
136         InstEncoderState               state;
137     public:
InstEncoder(const EncoderOpts & _opts,BitProcessor & _parent,const Model & _model)138         InstEncoder(
139             const EncoderOpts &_opts,
140             BitProcessor &_parent,
141             const Model &_model)
142             : BitProcessor(_parent)
143             , opts(_opts)
144             , model(_model) { }
145         InstEncoder(const InstEncoder&) = delete;
146 
getBackpatches()147         BackpatchList &getBackpatches() {return backpatches;}
148 
getInst() const149         const Instruction &getInst() const {return *state.inst;}
getOpSpec() const150         const OpSpec &getOpSpec() const {return getInst().getOpSpec();}
getModel() const151         const Model &getModel() const {return model;}
platform() const152         Platform platform() const {return getModel().platform;}
153 
154 //        void setBits(MInst mi) {*bits = mi;}
155 //        MInst getBits() const {return *bits;}
156 
157         ////////////////////////////////////////////////////////////////////////
158         // external interface (called by parent encoder; e.g. SerialEncoder)  //
159         ////////////////////////////////////////////////////////////////////////
160 
161         // Called externally by our parent encoder algorithm to start the encoding
162         // of an instruction.  The instruction size is determined by the compaction
163         // bit in the target instruction.
encodeInstruction(int ix,const Instruction & i,MInst * _bits)164         void encodeInstruction(
165             int ix,
166             const Instruction &i,
167             MInst *_bits)
168         {
169             setCurrInst(&i);
170 
171             state.instIndex = ix;
172             state.inst = &i;
173 #ifdef IGA_VALIDATE_BITS
174             state.dirty.qw0 = 0;
175             state.dirty.qw1 = 0;
176             state.fragmentsSet.clear();
177 #endif
178             memset(_bits, 0, sizeof(*_bits));
179             bits = _bits;
180             encodeForPlatform(i);
181         }
182 
resolveBackpatch(Backpatch & bp,MInst * _bits)183         void resolveBackpatch(Backpatch &bp, MInst *_bits) {
184             bits = _bits;
185             state = bp.state;
186             setCurrInst(bp.state.inst);
187             if (bp.type == Backpatch::ABS) {
188                 encode(bp.fragment, bp.target->getPC());
189             } else {
190                 encode(bp.fragment, bp.target->getPC() - bp.state.inst->getPC());
191             }
192         }
193 
194         //////////////////////////////////////////////////////
195         // internal (to the encoder package, not private) instances of
196         // encodeForPlatform<P> and their subtrees will call these methods.
197         //////////////////////////////////////////////////////
registerBackpatch(const Field & f,const Block * b,Backpatch::Type t=Backpatch::Type::REL)198         void registerBackpatch(
199             const Field &f,
200             const Block *b,
201             Backpatch::Type t = Backpatch::Type::REL)
202         {
203             backpatches.emplace_back(state, b, f, t);
204         }
205 
encode(const Field & f,int32_t val)206         void encode(const Field &f, int32_t val) {encodeFieldBits(f, (uint32_t)val);}
encode(const Field & f,int64_t val)207         void encode(const Field &f, int64_t val) {encodeFieldBits(f, (uint64_t)val);}
encode(const Field & f,uint32_t val)208         void encode(const Field &f, uint32_t val) {encodeFieldBits(f, (uint64_t)val);}
encode(const Field & f,uint64_t val)209         void encode(const Field &f, uint64_t val) {encodeFieldBits(f, val);}
encode(const Field & f,bool val)210         void encode(const Field &f, bool val) {encodeFieldBits(f, val ? 1 : 0);}
211         void encode(const Field &f, const OpSpec &os);
212         void encode(const Field &f, ExecSize es);
213         void encode(const Field &f, MathMacroExt acc);
214         void encode(const Field &f, Region::Vert vt);
215         void encode(const Field &f, Region::Width wi);
216         void encode(const Field &f, Region::Horz hz);
217         void encode(const Field &f, SrcModifier mods);
218         template <OpIx IX>
219         void encodeSubreg(
220             const Field &f,
221             RegName reg,
222             RegRef rr,
223             Type ty);
224         void encodeReg(
225             const Field &fREGFILE,
226             const Field &fREG,
227             RegName reg,
228             int regNum);
229 
230         //////////////////////////////////////////////////////
231         // Helper Functions
232         //////////////////////////////////////////////////////
233         void encodeFieldBits(const Field &f, uint64_t val0);
234 
encodingError(const std::string & msg)235         void encodingError(const std::string &msg) {
236             encodingError("", msg);
237         }
encodingError(const Field * f,const std::string & msg)238         void encodingError(const Field *f, const std::string &msg) {
239             encodingError(f ? f->name : "", msg);
240         }
encodingError(const Field & f,const std::string & msg)241         void encodingError(const Field &f, const std::string &msg) {
242             encodingError(f.name, msg);
243         }
encodingError(OpIx ix,const std::string & msg)244         void encodingError(OpIx ix, const std::string &msg) {
245             encodingError(ToStringOpIx(ix), msg);
246         }
encodingError(const std::string & ctx,const std::string & msg)247         void encodingError(const std::string &ctx, const std::string &msg) {
248             if (ctx.empty()) {
249                 errorT(msg);
250             } else {
251                 errorT(ctx, ": ", msg);
252             }
253         }
internalErrorBadIR(const std::string & what)254         void internalErrorBadIR(const std::string &what) {
255             errorT("INTERNAL ERROR: malformed IR: ", what);
256         }
internalErrorBadIR(const Field & f,const char * msg=nullptr)257         void internalErrorBadIR(const Field &f, const char *msg = nullptr) {
258             if (msg) {
259                 internalErrorBadIR(iga::format(f.name, ": ", msg));
260             } else {
261                 internalErrorBadIR(f.name);
262             }
263         }
264 
265         template <typename T>
encodeEnum(const Field & f,T lo,T hi,T x)266         void encodeEnum(const Field &f, T lo, T hi, T x) {
267             if (x < lo || x > hi) {
268                 encodingError(f, "invalid value");
269             }
270             encodeFieldBits(f, static_cast<uint64_t>(x));
271         }
272     private:
273 #ifdef IGA_VALIDATE_BITS
274         void reportFieldOverlap(const Fragment &fr);
275 #endif
276     private:
277         void encodeForPlatform(const Instruction &i);
278         void encodeForPlatformFamilyXE(const Instruction &i);
279     }; // end class InstEncoder
280 
281     ///////////////////////////////////////////////////////////////////////////
282     // longer method implementations (declared above)
283     ///////////////////////////////////////////////////////////////////////////
284 
encode(const Field & f,const OpSpec & os)285     inline void InstEncoder::encode(const Field &f, const OpSpec &os)
286     {
287         if (!os.isValid()) {
288             encodingError(f, "invalid opcode");
289         }
290         encodeFieldBits(f, os.opcode);
291     }
292 
293 #define ENCODING_CASE(X, V) case X: val = (V); break
encode(const Field & f,ExecSize es)294     inline void InstEncoder::encode(const Field &f, ExecSize es)
295     {
296         uint64_t val = 0;
297         switch (es) {
298         ENCODING_CASE(ExecSize::SIMD1,  0);
299         ENCODING_CASE(ExecSize::SIMD2,  1);
300         ENCODING_CASE(ExecSize::SIMD4,  2);
301         ENCODING_CASE(ExecSize::SIMD8,  3);
302         ENCODING_CASE(ExecSize::SIMD16, 4);
303         ENCODING_CASE(ExecSize::SIMD32, 5);
304         default: internalErrorBadIR(f);
305         }
306         encodeFieldBits(f, val);
307     }
308 
309     // encodes this as an math macro operand reference (e.g. r12.mme2)
310     // *not* as an explicit operand (for context save and restore)
encode(const Field & f,MathMacroExt mme)311     inline void InstEncoder::encode(const Field &f, MathMacroExt mme) {
312         uint64_t val = 0;
313         switch (mme) {
314         ENCODING_CASE(MathMacroExt::MME0, 0x0);
315         ENCODING_CASE(MathMacroExt::MME1, 0x1);
316         ENCODING_CASE(MathMacroExt::MME2, 0x2);
317         ENCODING_CASE(MathMacroExt::MME3, 0x3);
318         ENCODING_CASE(MathMacroExt::MME4, 0x4);
319         ENCODING_CASE(MathMacroExt::MME5, 0x5);
320         ENCODING_CASE(MathMacroExt::MME6, 0x6);
321         ENCODING_CASE(MathMacroExt::MME7, 0x7);
322         ENCODING_CASE(MathMacroExt::NOMME, 0x8);
323         default: internalErrorBadIR(f);
324         }
325         encodeFieldBits(f, val);
326     }
327 
encode(const Field & f,Region::Vert vt)328     inline void InstEncoder::encode(const Field &f, Region::Vert vt)
329     {
330         uint64_t val = 0;
331         switch (vt) {
332         ENCODING_CASE(Region::Vert::VT_0,  0x0);
333         ENCODING_CASE(Region::Vert::VT_1,  0x1);
334         ENCODING_CASE(Region::Vert::VT_2,  0x2);
335         ENCODING_CASE(Region::Vert::VT_4,  0x3);
336         ENCODING_CASE(Region::Vert::VT_8,  0x4);
337         ENCODING_CASE(Region::Vert::VT_16, 0x5);
338         ENCODING_CASE(Region::Vert::VT_32, 0x6);
339         case Region::Vert::VT_VxH:
340             val = 0xF;
341             if (f.encodedLength() == 3) {
342                 val = 0x7; // XeHPC+
343             }
344             break;
345         default: internalErrorBadIR(f);
346         }
347         encodeFieldBits(f, val);
348     }
349 
encode(const Field & f,Region::Width wi)350     inline void InstEncoder::encode(const Field &f, Region::Width wi) {
351         uint64_t val = 0;
352         switch (wi) {
353         ENCODING_CASE(Region::Width::WI_1,  0x0);
354         ENCODING_CASE(Region::Width::WI_2,  0x1);
355         ENCODING_CASE(Region::Width::WI_4,  0x2);
356         ENCODING_CASE(Region::Width::WI_8,  0x3);
357         ENCODING_CASE(Region::Width::WI_16, 0x4);
358         default: internalErrorBadIR(f);
359         }
360         encodeFieldBits(f, val);
361     }
362 
encode(const Field & f,Region::Horz hz)363     inline void InstEncoder::encode(const Field &f, Region::Horz hz) {
364         uint64_t val = 0;
365         switch (hz) {
366         ENCODING_CASE(Region::Horz::HZ_0, 0);
367         ENCODING_CASE(Region::Horz::HZ_1, 1);
368         ENCODING_CASE(Region::Horz::HZ_2, 2);
369         ENCODING_CASE(Region::Horz::HZ_4, 3);
370         default: internalErrorBadIR(f);
371         }
372         encodeFieldBits(f, val);
373     }
374 
encode(const Field & f,SrcModifier mods)375     inline void InstEncoder::encode(const Field &f, SrcModifier mods) {
376         uint64_t val = 0;
377         switch (mods) {
378         ENCODING_CASE(SrcModifier::NONE, 0x0);
379         ENCODING_CASE(SrcModifier::ABS, 0x1);
380         ENCODING_CASE(SrcModifier::NEG, 0x2);
381         ENCODING_CASE(SrcModifier::NEG_ABS, 0x3);
382         default: internalErrorBadIR(f);
383         }
384         encodeFieldBits(f, val);
385     }
386 #undef ENCODING_CASE
387 
encodeReg(const Field & fREGFILE,const Field & fREG,RegName reg,int regNum)388     inline void InstEncoder::encodeReg(
389         const Field &fREGFILE,
390         const Field &fREG,
391         RegName reg,
392         int regNum)
393     {
394         const RegInfo *ri = model.lookupRegInfoByRegName(reg);
395         if (ri == nullptr) {
396             internalErrorBadIR(fREG, "unsupported register for platform");
397             return;
398         }
399         uint8_t regNumBits = 0;
400         if (!ri->encode(regNum, regNumBits)) {
401             internalErrorBadIR(fREG, "invalid register");
402             return;
403         }
404         encodeFieldBits(fREGFILE, reg == RegName::GRF_R ? 1 : 0);
405         encodeFieldBits(fREG, regNumBits);
406     }
407 
408     template <OpIx IX>
encodeSubreg(const Field & f,RegName reg,RegRef rr,Type ty)409     inline void InstEncoder::encodeSubreg(
410         const Field &f, RegName reg, RegRef rr, Type ty)
411     {
412         uint64_t val = (uint64_t)rr.subRegNum;
413         // branches have implicit :d
414         val = ty == Type::INVALID ? 4*val :
415             SubRegToBinaryOffset((int)val, reg, ty, model.platform);
416         if (platform() >= Platform::XE_HPC &&
417             reg == RegName::ARF_FC)
418         {
419             val = 2 * val;
420         }
421         encodeFieldBits(f, val);
422     }
423 
424 
encodeForPlatform(const Instruction & i)425     inline void InstEncoder::encodeForPlatform(const Instruction &i)
426     {
427         switch (platform()) {
428         case Platform::XE:
429         case Platform::XE_HP:
430         case Platform::XE_HPG:
431         case Platform::XE_HPC:
432         case Platform::FUTURE:
433         default:
434             // caller checks this and gives a soft error
435             IGA_ASSERT_FALSE("unsupported platform for native encoder");
436         }
437     }
438 } // end iga::*
439 #endif /* IGA_BACKEND_NATIVE_INSTENCODER_HPP */
440