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 _G4_OPCODE_H_
10 #define _G4_OPCODE_H_
11 #include "visa_igc_common_header.h"
12 #include "common.h"
13 
14 #define G4_MAX_SRCS       4
15 #define G4_MAX_INTRINSIC_SRCS       8
16 #define UNDEFINED_VAL   0xFFFFFFFF
17 #define UNDEFINED_SHORT 0x8000
18 #define UNDEFINED_EXEC_SIZE 0xFF
19 
20 #define G4_WSIZE 2            // 2 bytes 16 bits
21 #define G4_DSIZE 4            // 4 bytes 32 bits
22 #define IS_FTYPE(x) ((x) == Type_F)
23 #define IS_HFTYPE(x) ((x) == Type_HF)
24 #define IS_DFTYPE(x) ((x) == Type_DF || (x) == Type_NF)
25 #define IS_DTYPE(x) ((x) == Type_D || (x) == Type_UD)
26 #define IS_VINTTYPE(x) ((x) == Type_V || (x) == Type_UV)
27 #define IS_VFTYPE(x) ((x) == Type_VF)
28 #define IS_VTYPE(x) (IS_VINTTYPE(x) || IS_VFTYPE(x))
29 #define IS_WTYPE(x) ((x) == Type_W || (x) == Type_UW || (x) == Type_HF)
30 #define IS_BTYPE(x) ((x) == Type_B || (x) == Type_UB)
31 #define IS_QTYPE(x) ((x) == Type_Q || (x) == Type_UQ)
32 #define IS_SIGNED_INT(x) ((x) == Type_B || (x) == Type_W || (x) == Type_D || (x) == Type_Q)
33 #define IS_UNSIGNED_INT(x) ((x) == Type_UB || (x) == Type_UW || (x) == Type_UD || (x) == Type_UQ)
34 #define IS_INT(x) (IS_SIGNED_INT(x) || IS_UNSIGNED_INT(x))
35 #define IS_TYPE_INT(type)        (IS_SIGNED_INT(type) || IS_UNSIGNED_INT(type))
36 #define IS_TYPE_F32_F64(type)         (type == Type_F ||type == Type_DF || type == Type_NF)
37 #define IS_TYPE_FLOAT_ALL(type)     (type == Type_F ||type == Type_DF || type == Type_HF || type == Type_NF || type == Type_BF)
38 #define IS_TYPE_FLOAT_FOR_ACC(type)     (type == Type_F ||type == Type_DF || type == Type_HF)
39 #define IS_TYPE_LONG(type)            (type == Type_DF || type == Type_UQ || type == Type_Q)
40 #define IS_TYPE_INTEGER(type)         (type == Type_UW ||type == Type_W ||type == Type_B ||type == Type_UB ||type == Type_V ||type == Type_UV ||type == Type_UD ||type == Type_D)
41 
42 #define GENX_DATAPORT_IO_SZ (getGRFSize() == 64 ? 16 : 8)
43 #define GENX_SAMPLER_IO_SZ GENX_DATAPORT_IO_SZ
44 
45 #define ADDR_REG_TYPE        Type_UW
46 
47 #include "VISADefines.h"
48 
49 // ToDo: move them to common.h?
50 #define MAKE_ENUM(X) X,
51 #define STRINGIFY(X) #X,
52 
53 enum class BankAlign
54 {
55     Either    = 1, // either
56     Even      = 2, // even align
57     Odd       = 3, // old align
58     Even2GRF  = 4, // 2-GRF even align 1100
59     Odd2GRF   = 5, // 2-GRF old align, 0011
60     Align_NUM = 6  // Num of alignment
61 };
62 
63 // An instruction's execution width
64 struct G4_ExecSize {
65     unsigned char value;
66 
67     // goal is to keep constructors "explicit" so they
68     // better distingushed in parameter lists for overload resolution
G4_ExecSizeG4_ExecSize69     explicit constexpr G4_ExecSize(unsigned char _value) : value(_value) { }
70     // we could provide a non-const version of these that asserts on SIMD sizes
G4_ExecSizeG4_ExecSize71     explicit G4_ExecSize(int _value) : value((unsigned)_value) { }
G4_ExecSizeG4_ExecSize72     explicit G4_ExecSize(unsigned int _value) : value(_value) { }
73     // the default constructor can be implicit
G4_ExecSizeG4_ExecSize74     constexpr G4_ExecSize() : value(0) { }
75 
76     G4_ExecSize(const G4_ExecSize &) = default;
77     G4_ExecSize &operator =(const G4_ExecSize &) = default;
78 
79     G4_ExecSize &operator *=(unsigned char s) {value *= s; return *this;}
80     G4_ExecSize &operator /=(unsigned char s) {value /= s; return *this;}
81 
82     bool operator < (G4_ExecSize rhs) const {return value < rhs.value;}
83     bool operator <=(G4_ExecSize rhs) const {return value <= rhs.value;}
84     bool operator ==(G4_ExecSize rhs) const {return value == rhs.value;}
85     bool operator !=(G4_ExecSize rhs) const {return value != rhs.value;}
86     bool operator >=(G4_ExecSize rhs) const {return value >= rhs.value;}
87     bool operator > (G4_ExecSize rhs) const {return value > rhs.value;}
88 
89     bool operator < (unsigned rhs) const {return value < (unsigned char)rhs;}
90     bool operator <=(unsigned rhs) const {return value <= (unsigned char)rhs;}
91     bool operator ==(unsigned rhs) const {return value == (unsigned char)rhs;}
92     bool operator !=(unsigned rhs) const {return value != (unsigned char)rhs;}
93     bool operator >=(unsigned rhs) const {return value >= (unsigned char)rhs;}
94     bool operator > (unsigned rhs) const {return value > (unsigned char)rhs;}
95 
96     bool operator < (int rhs) const {return value < (unsigned char)rhs;}
97     bool operator <=(int rhs) const {return value <= (unsigned char)rhs;}
98     bool operator ==(int rhs) const {return value == (unsigned char)rhs;}
99     bool operator !=(int rhs) const {return value != (unsigned char)rhs;}
100     bool operator >=(int rhs) const {return value >= (unsigned char)rhs;}
101     bool operator > (int rhs) const {return value > (unsigned char)rhs;}
102 
103     operator unsigned char() const {return value;}
104 };
105 namespace g4 {
106 constexpr G4_ExecSize SIMD1((unsigned char)1);
107 constexpr G4_ExecSize SIMD2((unsigned char)2);
108 constexpr G4_ExecSize SIMD4((unsigned char)4);
109 constexpr G4_ExecSize SIMD8((unsigned char)8);
110 constexpr G4_ExecSize SIMD16((unsigned char)16);
111 constexpr G4_ExecSize SIMD32((unsigned char)32);
112 // TODO: remove/merge with G4_ExecSize(0) uses
113 constexpr G4_ExecSize SIMD_UNDEFINED((unsigned char)UNDEFINED_EXEC_SIZE);
114 }
115 
116 namespace g4 {
117     template <typename T>
alignUp(T a,T n)118     static inline T alignUp(T a, T n) {
119         return ((n + a - 1) - (n + a - 1) % a);
120     }
121 }
122 
123 // saturation
124 // (typesafe enum value with operators and conversions)
125 //
126 // use g4::SAT or g4::NOSAT to reference the two values
127 struct G4_Sat {
128     const enum class Value {NOSAT = 0, SAT} value;
G4_SatG4_Sat129     constexpr G4_Sat(Value _value) : value(_value) { }
130     operator bool () const {return value == Value::SAT;}
131 };
132 namespace g4 {
133     // enables g4::SAT as a symbol for a short-hand saturation
134     constexpr G4_Sat SAT(G4_Sat::Value::SAT);
135     constexpr G4_Sat NOSAT(G4_Sat::Value::NOSAT);
136 }
137 
138 
139 // To support sub register alignment
140 enum G4_SubReg_Align
141 {
142     Any = 1,
143     Even_Word = 2,
144     Four_Word = 4,
145     Eight_Word = 8,
146     Sixteen_Word = 16,
147     ThirtyTwo_Word = 32
148 };
149 
150 
151 enum G4_SrcModifier
152 {
153     Mod_Minus = 0,        // "-", negative
154     Mod_Abs,            // (abs), absolute value
155     Mod_Minus_Abs,        // -(abs)
156     Mod_Not,            // invert (for BDW logic instruction)
157     Mod_src_undef        // undefined
158 };
159 
160 enum G4_CondModifier
161 {
162     Mod_z = 0,            // zero
163     Mod_e,                // equal
164     Mod_nz,                // not zero
165     Mod_ne,                // not equal
166     Mod_g,                // greater
167     Mod_ge,                // greater or equal
168     Mod_l,                // less
169     Mod_le,                // less or equal
170     Mod_o,                // overflow
171     Mod_r,                // round increment
172     Mod_u,                // unorder (NaN)
173     Mod_cond_undef        // undefined
174 };
175 
176 enum G4_PredState
177 {
178     PredState_Plus = 0, // +
179     PredState_Minus,    // -
180     PredState_undef     // undefined
181 };
182 
183 enum G4_RegAccess {
184     Direct,
185     IndirGRF,
186 };
187 
188 //
189 // register and Imm data type
190 // Note: Check G4_Type_ByteFootprint if this is modified
191 //
192 enum G4_Type
193 {
194     Type_UD = 0,// unsigned double word integer
195     Type_D,        // signed double word integer
196     Type_UW,    // unsigned word integer
197     Type_W,        // signed word integer
198     Type_UB,    // unsigned byte integer
199     Type_B,        // signed byte integer
200     Type_F,        // signed single precision
201     Type_VF,    // 32-bit restricted Vector Float
202     Type_V,     // 32-bit halfbyte integer Vector
203     Type_DF,
204     Type_BOOL,
205     Type_UV,
206     Type_Q,     // 64-bit signed integer
207     Type_UQ,    // 64-bit unsigned integer
208     Type_HF,    // half float
209     Type_NF,    // native float (only used by plane macro)
210     Type_BF,    // bfloat16 (used in mov only)
211     Type_UNDEF
212 };
213 
214 typedef struct
215 {
216     G4_Type type;
217     unsigned char bitSize;
218     unsigned char byteSize;
219     unsigned char footprint; // bit pattern that corresponds to type's byte usage
220     const char *syntax; // constant string representation of the type
221 } G4_Type_Info;
222 
223 constexpr G4_Type_Info G4_Type_Table[Type_UNDEF + 1] {
224     {Type_UD,  32, 4, 0x0F, "ud"},
225     {Type_D,   32, 4, 0x0F, "d"},
226     {Type_UW,  16, 2, 0x03, "uw"},
227     {Type_W,   16, 2, 0x03, "w"},
228     {Type_UB,   8, 1, 0x01, "ub"},
229     {Type_B,    8, 1, 0x01, "b"},
230     {Type_F,   32, 4, 0x0F, "f"},
231     {Type_VF,  32, 4, 0x0F, "vf"}, // handle as F?
232     {Type_V,   32, 4, 0x0F, "v"},  // handle as D?
233     {Type_DF,  64, 8, 0xFF, "df"},
234     {Type_BOOL, 1, 2, 0x01, "bool"}, // TODO: how to decide 1 bit here?
235     {Type_UV,  32, 4, 0x0F, "uv"},
236     {Type_Q,   64, 8, 0xFF, "q"},
237     {Type_UQ,  64, 8, 0xFF, "uq"},
238     {Type_HF,  16, 2, 0x03, "hf"},
239     {Type_NF,  64, 8, 0xFF, "nf"},
240     {Type_BF,  16, 2, 0x03, "bf"},
241     {Type_UNDEF, 0, 0, 0x0, "???"}
242 };
TypeInfo(G4_Type t)243 static inline constexpr G4_Type_Info TypeInfo(G4_Type t) {
244     return G4_Type_Table[(unsigned)t > (unsigned)Type_UNDEF ? Type_UNDEF : t];
245 }
TypeSize(G4_Type t)246 static inline constexpr unsigned short TypeSize(G4_Type t)
247 {
248     return TypeInfo(t).byteSize;
249 }
TypeBitSize(G4_Type t)250 static inline constexpr unsigned short TypeBitSize(G4_Type t)
251 {
252     // TODO: can we use TypeBitSize/8 here? Need to determine why bool is 2 B
253     return TypeInfo(t).bitSize;
254 }
TypeFootprint(G4_Type t)255 static inline constexpr unsigned short TypeFootprint(G4_Type t)
256 {
257     return TypeInfo(t).footprint;
258 }
TypeSymbol(G4_Type t)259 static inline constexpr const char * TypeSymbol(G4_Type t)
260 {
261     return TypeInfo(t).syntax;
262 }
263 
264 enum G4_InstType
265 {
266     InstTypeMov        = 0,    // mov or sel
267     InstTypeLogic,            // not, and, or, xor, ...
268     InstTypeCompare,        // cmp, cmpn
269     InstTypeFlow,            // if, iff, do, while, break, ...
270     InstTypeArith,            // add, mul, frc, mac , ...
271     InstTypeVector,            // sad, sad2, dp4, dp3, dp2, ..
272     InstTypeMisc,            // send, wait, nop, illegal
273     InstTypePseudoLogic,    // Pseudo_not, Pseudo_and, ...
274     InstTypeReserved        // reserved (unused)
275 };
276 
277 enum G4_RegFileKind
278 {
279     G4_UndefinedRF = 0x0,
280     G4_GRF         = 0x1,   // general register file
281     G4_ADDRESS     = 0x2,   // architectural register file
282     G4_INPUT       = 0x4,   // input payload register
283     G4_FLAG        = 0x20,
284     G4_SCALAR      = 0x40,
285 };
286 
287 //
288 // multiple options can coexist so we define one bit for each option
289 //
290 enum G4_InstOption
291 {
292     InstOpt_NoOpt       = 0x0,
293     InstOpt_Align16     = 0x00000002,
294     InstOpt_M0          = 0x00100000,
295     InstOpt_M4          = 0x00200000,
296     InstOpt_M8          = 0x00400000,
297     InstOpt_M12         = 0x00800000,
298     InstOpt_M16         = 0x01000000,
299     InstOpt_M20         = 0x02000000,
300     InstOpt_M24         = 0x04000000,
301     InstOpt_M28         = 0x08000000,
302     InstOpt_Switch      = 0x00000010,
303     InstOpt_Atomic      = 0x00000020,
304     InstOpt_NoDDChk     = 0x00000040,
305     InstOpt_NoDDClr     = 0x00000080,
306     InstOpt_WriteEnable = 0x00000100,
307 
308     InstOpt_BreakPoint  = 0x00000200,
309     InstOpt_EOT         = 0x00000400,
310     InstOpt_AccWrCtrl   = 0x00000800,
311     InstOpt_NoCompact   = 0x00001000,
312     InstOpt_Compacted   = 0x00002000,
313     InstOpt_NoSrcDepSet = 0x00004000,
314     InstOpt_NoPreempt   = 0x00008000,
315     InstOpt_Serialize   = 0x0001000,
316 
317     InstOpt_END         = 0xFFFFFFFF
318 };
319 
320 
321 #define InstOpt_QuarterMasks \
322     (InstOpt_M0 | InstOpt_M4 | InstOpt_M8 | InstOpt_M12 | InstOpt_M16 | InstOpt_M20 | InstOpt_M24 | InstOpt_M28)
323 #define InstOpt_Masks (InstOpt_QuarterMasks | InstOpt_WriteEnable)
324 
325 // TODO: to a more proper data type
326 // ==> step 1: use uint32_t so all the untyped uses still compile
327 //             but replace all uint32_t (and other int types with G4_InstOpts)
328 //     step 2: make G4_InstOpts a typesafe enum;
329 //             #define old unscoped enum names to new typesafe enum
330 //             (define various set operators so |, &, and ~ still work)
331 //             remove the few magic number uses with valid type enumes
332 //     step 3: mechanically (find and replace) old unscoped enums with
333 //             typesafe symbols and remove #defines
334 using G4_InstOpts = uint32_t;
335 
336 
337 typedef struct _G4_InstOptInfo
338 {
339     G4_InstOption optMask;
340     const char*   optStr;
341 } G4_InstOptInfo;
342 
343 
344 
345 //various attributes for the Gen opcodes
346 #define ATTR_NONE               0x00000000
347 #define ATTR_PSEUDO             0x00000001
348 #define ATTR_COMMUTATIVE        0x00000002
349 #define ATTR_FLOAT_SRC_ONLY     0x00000004
350 #define ATTR_WIDE_DST           0x00000008
351 
352 #define INST_PSEUDO(inst)           (G4_Inst_Table[inst].attributes & ATTR_PSEUDO)
353 #define INST_COMMUTATIVE(inst)      (G4_Inst_Table[inst].attributes & ATTR_COMMUTATIVE)
354 #define INST_FLOAT_SRC_ONLY(inst)   (G4_Inst_Table[inst].attributes & ATTR_FLOAT_SRC_ONLY)
355 #define INST_WIDE_DST(inst)         (G4_Inst_Table[inst].attributes & ATTR_WIDE_DST)
356 
357 #define HANDLE_INST(op, nsrc, ndst, type, plat, attr) G4_ ## op,
358 
359 enum G4_opcode
360 {
361 #include "G4Instruction.h"
362     G4_NUM_OPCODE
363 };
364 
365 
366 typedef struct _G4_Inst_Info
367 {
368     G4_opcode   op;       // just for debugging purpose
369     const char* str;      // for emitting asm code
370     uint8_t     n_srcs;   // # of source operands
371     uint8_t     n_dst;    // # of dst operands
372     G4_InstType instType; // inst classification
373     TARGET_PLATFORM    platform; // The platform that first supports this inst.
374     int         attributes;
375 } G4_Inst_Info;
376 
377 // ToDo: make this into G4_INST so that not everyone and their grandma are directly reading it
378 extern const G4_Inst_Info G4_Inst_Table[G4_NUM_OPCODE+1];
379 
380 // Relation between two regions. The comparison is based on memory locations
381 // regions reference, which are described by the left-bound, the right bound,
382 // and their footprint vectors. The exact order of elements or type are not
383 // considered. For example, region comparison algorithm will return Rel_eq for
384 // the following region pairs:
385 //
386 // * (8) V(0,0)<1>:d and (8) V(0,0)<1;4,2>:d
387 // * (8) V(0,0)<1>:d and (16) V(0,0)<1;1,0>:w
388 // * (8) V(0,0)<1>:d and (16) V(0,0)<0;8,1>:d
389 //
390 enum G4_CmpRelation
391 {
392     Rel_eq = 0,        // region A is the same as region B
393     Rel_lt,            // region A is a subset of region B
394     Rel_gt,            // region A is a super set of region B
395     Rel_interfere,     // region A overlaps with region B
396     Rel_disjoint,      // region A and region B are disjoint
397     Rel_undef          // region A and region B have different base variable
398 };
399 
400 #define OPND_NUM_ENUM(DO) \
401     DO(Opnd_dst) \
402     DO(Opnd_src0) \
403     DO(Opnd_src1) \
404     DO(Opnd_src2) \
405     DO(Opnd_src3) \
406     DO(Opnd_src4) \
407     DO(Opnd_src5) \
408     DO(Opnd_src6) \
409     DO(Opnd_src7) \
410     DO(Opnd_pred) \
411     DO(Opnd_condMod) \
412     DO(Opnd_implAccSrc) \
413     DO(Opnd_implAccDst) \
414     DO(Opnd_total_num)
415 
416 enum Gen4_Operand_Number
417 {
418     OPND_NUM_ENUM(MAKE_ENUM)
419 };
420 
421 enum G4_ArchRegKind {
422     // Note that the enum values are different from HW values,
423     // as we represent acc0 and acc1 as different AReg for example
424     AREG_NULL = 0, // null register
425     AREG_A0,          // address register
426     AREG_ACC0,        // accumulator register
427     AREG_ACC1,        // accumulator register
428     AREG_MASK0,       // mask register
429     AREG_MS0,         // mask stack register
430     AREG_DBG,         // mask stack depth register
431     AREG_SR0,         // state register
432     AREG_CR0,         // control register
433     AREG_N0,          // notification count register
434     AREG_N1,          // notification count register
435     AREG_IP,          // instruction pointer register
436     AREG_F0,          // flag register
437     AREG_F1,          // flag register
438     AREG_TM0,         // timestamp register
439     AREG_TDR0,        // TDR register
440     AREG_SP,          // SP register
441     AREG_F2,          // flag register (PVC+)
442     AREG_F3,          // flag register (PVC+)
443     AREG_LAST
444 };
445 
446 enum G4_AccRegSel
447 {
448     ACC2 = 0,
449     ACC3,
450     ACC4,
451     ACC5,
452     ACC6,
453     ACC7,
454     ACC8,
455     ACC9,
456     NOACC,
457     ACC_UNDEFINED = 0xff
458 };
459 
460 #define GRFALIGN (getGRFSize() == 64 ? ThirtyTwo_Word : Sixteen_Word)
461 #define HALFGRFALIGN (getGRFSize() == 64 ? Sixteen_Word : Eight_Word)
462 
463 // global functions
getNumAddrRegisters(void)464 inline unsigned int getNumAddrRegisters(void) { return 16; }
465 uint8_t roundDownPow2(uint8_t n);
466 
467 // G4_type related global functions
isLowPrecisionFloatTy(G4_Type ty)468 inline bool isLowPrecisionFloatTy(G4_Type ty)
469 {
470     return ty == Type_HF || ty == Type_BF;
471 }
472 
floatToSameWidthIntType(G4_Type floatTy)473 inline G4_Type floatToSameWidthIntType(G4_Type floatTy)
474 {
475     assert(IS_TYPE_FLOAT_ALL(floatTy));
476     switch (TypeSize(floatTy))
477     {
478     case 1:
479         return Type_UB;
480     case 2:
481         return Type_UW;
482     case 4:
483         return Type_UD;
484     case 8:
485         return Type_UQ;
486     default:
487         assert(false && "illegal type size");
488         return Type_UD;
489     }
490 }
491 
492 // size is the number of byte
Get_G4_SubRegAlign_From_Size(uint16_t size)493 inline G4_SubReg_Align Get_G4_SubRegAlign_From_Size(uint16_t size)
494 {
495     switch (size)
496     {
497     case 1:
498     case 2:
499         return Any;
500     case 4:
501         return Even_Word;
502     case 8:
503         if (getGenxPlatform() != GENX_BXT)
504             return Four_Word;
505         // FALL THROUGH
506         // WA: It's a workaround where a potential HW issue needs
507         // identifying.
508     case 16:
509         return Eight_Word;
510     case 32:
511         return Sixteen_Word;
512     case 64:
513         return ThirtyTwo_Word;
514     default:
515         return GRFALIGN;
516     }
517 }
518 
Get_G4_SubRegAlign_From_Type(G4_Type ty)519 inline G4_SubReg_Align Get_G4_SubRegAlign_From_Type(G4_Type ty)
520 {
521     switch (ty)
522     {
523     case Type_B:
524     case Type_UB:
525     case Type_W:
526     case Type_UW:
527         return Any;
528     case Type_UD:
529     case Type_D:
530     case Type_F:
531         return Even_Word;
532     case Type_DF:
533         return Four_Word;
534     case Type_V:
535     case Type_VF:
536     case Type_UV:
537         return Eight_Word;
538     case Type_Q:
539     case Type_UQ:
540         return Four_Word;
541     default:
542         return Any;
543     }
544 }
545 #endif  // _G4_OPCODE_H_
546