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