File: G4_Opcode.h

package info (click to toggle)
intel-graphics-compiler2 2.24.13-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 113,504 kB
  • sloc: cpp: 812,849; lisp: 288,219; ansic: 102,423; python: 4,010; yacc: 2,588; lex: 1,666; pascal: 318; sh: 162; makefile: 38
file content (525 lines) | stat: -rw-r--r-- 18,136 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
/*========================== begin_copyright_notice ============================

Copyright (C) 2017-2021 Intel Corporation

SPDX-License-Identifier: MIT

============================= end_copyright_notice ===========================*/

#ifndef _G4_OPCODE_H_
#define _G4_OPCODE_H_
#include "Assertions.h"
#include "common.h"
#include "visa_igc_common_header.h"

// TODO: Probably should get rid of G4_MAX_SRCS constant at some point.
#define G4_MAX_SRCS 5
#define G4_MAX_INTRINSIC_SRCS 8
#define UNDEFINED_VAL 0xFFFFFFFF
#define UNDEFINED_SHORT 0x8000
#define UNDEFINED_EXEC_SIZE 0xFF

#define G4_WSIZE 2 // 2 bytes 16 bits
#define G4_DSIZE 4 // 4 bytes 32 bits
#define IS_FTYPE(x) ((x) == Type_F)
#define IS_HFTYPE(x) ((x) == Type_HF)
#define IS_BFTYPE(x) ((x) == Type_BF)
#define IS_DFTYPE(x) ((x) == Type_DF || (x) == Type_NF)
#define IS_DTYPE(x) ((x) == Type_D || (x) == Type_UD)
#define IS_VINTTYPE(x) ((x) == Type_V || (x) == Type_UV)
#define IS_VFTYPE(x) ((x) == Type_VF)
#define IS_VTYPE(x) (IS_VINTTYPE(x) || IS_VFTYPE(x))
#define IS_WTYPE(x) ((x) == Type_W || (x) == Type_UW || (x) == Type_HF)
#define IS_BTYPE(x) ((x) == Type_B || (x) == Type_UB)
#define IS_QTYPE(x) ((x) == Type_Q || (x) == Type_UQ)
#define IS_SIGNED_INT(x)                                                       \
  ((x) == Type_B || (x) == Type_W || (x) == Type_D || (x) == Type_Q)
#define IS_UNSIGNED_INT(x)                                                     \
  ((x) == Type_UB || (x) == Type_UW || (x) == Type_UD || (x) == Type_UQ)
#define IS_INT(x) (IS_SIGNED_INT(x) || IS_UNSIGNED_INT(x))
#define IS_TYPE_INT(type) (IS_SIGNED_INT(type) || IS_UNSIGNED_INT(type))
#define IS_TYPE_F32_F64(type)                                                  \
  (type == Type_F || type == Type_DF || type == Type_NF)
#define IS_TYPE_FLOAT_ALL(type)                                                \
  (type == Type_F || type == Type_DF || type == Type_HF || type == Type_NF ||  \
   type == Type_BF)
#define IS_TYPE_FLOAT_FOR_ACC(type)                                            \
  (type == Type_F || type == Type_DF || type == Type_HF)
#define IS_TYPE_LONG(type)                                                     \
  (type == Type_DF || type == Type_UQ || type == Type_Q)
#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)

#define ADDR_REG_TYPE Type_UW

// ToDo: move them to common.h?
#define MAKE_ENUM(X) X,
#define STRINGIFY(X) #X,

enum class BankAlign {
  Either = 1,   // either
  Even = 2,     // even align
  Odd = 3,      // old align
  Even2GRF = 4, // 2-GRF even align 1100
  Odd2GRF = 5,  // 2-GRF old align, 0011
  QuadGRF = 6,  // 4-GRF align
  Align_NUM = 7 // Num of alignment
};

// An instruction's execution width
struct G4_ExecSize {
  unsigned char value;

  // goal is to keep constructors "explicit" so they
  // better distingushed in parameter lists for overload resolution
  explicit constexpr G4_ExecSize(unsigned char _value) : value(_value) {}
  // we could provide a non-const version of these that asserts on SIMD sizes
  explicit G4_ExecSize(int _value) : value((unsigned)_value) {}
  explicit G4_ExecSize(unsigned int _value) : value(_value) {}
  // the default constructor can be implicit
  constexpr G4_ExecSize() : value(0) {}

  G4_ExecSize(const G4_ExecSize &) = default;
  G4_ExecSize &operator=(const G4_ExecSize &) = default;

  G4_ExecSize &operator*=(unsigned char s) {
    value *= s;
    return *this;
  }
  G4_ExecSize &operator/=(unsigned char s) {
    value /= s;
    return *this;
  }

  bool operator<(G4_ExecSize rhs) const { return value < rhs.value; }
  bool operator<=(G4_ExecSize rhs) const { return value <= rhs.value; }
  bool operator==(G4_ExecSize rhs) const { return value == rhs.value; }
  bool operator!=(G4_ExecSize rhs) const { return value != rhs.value; }
  bool operator>=(G4_ExecSize rhs) const { return value >= rhs.value; }
  bool operator>(G4_ExecSize rhs) const { return value > rhs.value; }

  bool operator<(unsigned rhs) const { return value < (unsigned char)rhs; }
  bool operator<=(unsigned rhs) const { return value <= (unsigned char)rhs; }
  bool operator==(unsigned rhs) const { return value == (unsigned char)rhs; }
  bool operator!=(unsigned rhs) const { return value != (unsigned char)rhs; }
  bool operator>=(unsigned rhs) const { return value >= (unsigned char)rhs; }
  bool operator>(unsigned rhs) const { return value > (unsigned char)rhs; }

  bool operator<(int rhs) const { return value < (unsigned char)rhs; }
  bool operator<=(int rhs) const { return value <= (unsigned char)rhs; }
  bool operator==(int rhs) const { return value == (unsigned char)rhs; }
  bool operator!=(int rhs) const { return value != (unsigned char)rhs; }
  bool operator>=(int rhs) const { return value >= (unsigned char)rhs; }
  bool operator>(int rhs) const { return value > (unsigned char)rhs; }

  operator unsigned char() const { return value; }
};
namespace g4 {
constexpr G4_ExecSize SIMD1((unsigned char)1);
constexpr G4_ExecSize SIMD2((unsigned char)2);
constexpr G4_ExecSize SIMD4((unsigned char)4);
constexpr G4_ExecSize SIMD8((unsigned char)8);
constexpr G4_ExecSize SIMD16((unsigned char)16);
constexpr G4_ExecSize SIMD32((unsigned char)32);
// TODO: remove/merge with G4_ExecSize(0) uses
constexpr G4_ExecSize SIMD_UNDEFINED((unsigned char)UNDEFINED_EXEC_SIZE);
} // namespace g4

namespace g4 {
template <typename T> static inline T alignUp(T a, T n) {
  return ((n + a - 1) - (n + a - 1) % a);
}
} // namespace g4

// saturation
// (typesafe enum value with operators and conversions)
//
// use g4::SAT or g4::NOSAT to reference the two values
struct G4_Sat {
  const enum class Value { NOSAT = 0, SAT } value;
  constexpr G4_Sat(Value _value) : value(_value) {}
  operator bool() const { return value == Value::SAT; }
};
namespace g4 {
// enables g4::SAT as a symbol for a short-hand saturation
constexpr G4_Sat SAT(G4_Sat::Value::SAT);
constexpr G4_Sat NOSAT(G4_Sat::Value::NOSAT);
} // namespace g4

// To support sub register alignment
enum G4_SubReg_Align {
  Any = 1,
  Even_Word = 2,
  Four_Word = 4,
  Eight_Word = 8,
  Sixteen_Word = 16,
  ThirtyTwo_Word = 32
};

enum G4_SrcModifier : unsigned char {
  Mod_Minus = 0, // "-", negative
  Mod_Abs,       // (abs), absolute value
  Mod_Minus_Abs, // -(abs)
  Mod_Not,       // invert (for BDW logic instruction)
  Mod_src_undef  // undefined
};

enum G4_CondModifier : unsigned char {
  Mod_z = 0,     // zero
  Mod_e,         // equal
  Mod_nz,        // not zero
  Mod_ne,        // not equal
  Mod_g,         // greater
  Mod_ge,        // greater or equal
  Mod_l,         // less
  Mod_le,        // less or equal
  Mod_o,         // overflow
  Mod_r,         // round increment
  Mod_u,         // unorder (NaN)
  Mod_cond_undef // undefined
};

enum G4_PredState : unsigned char {
  PredState_Plus = 0, // +
  PredState_Minus,    // -
  PredState_undef     // undefined
};

enum G4_RegAccess : unsigned char {
  Direct,
  IndirGRF,
};

//
// register and Imm data type
// Note: Check G4_Type_ByteFootprint if this is modified
//
enum G4_Type : unsigned char {
  Type_UD = 0, // unsigned double word integer
  Type_D,      // signed double word integer
  Type_UW,     // unsigned word integer
  Type_W,      // signed word integer
  Type_UB,     // unsigned byte integer
  Type_B,      // signed byte integer
  Type_F,      // signed single precision
  Type_VF,     // 32-bit restricted Vector Float
  Type_V,      // 32-bit halfbyte integer Vector
  Type_DF,
  Type_BOOL,
  Type_UV,
  Type_Q,  // 64-bit signed integer
  Type_UQ, // 64-bit unsigned integer
  Type_HF, // half float
  Type_NF, // native float (only used by plane macro)
  Type_BF, // bfloat16 (used in mov only)
  Type_UNDEF
};

typedef struct {
  G4_Type type;
  unsigned char bitSize;
  unsigned char byteSize;
  unsigned char footprint; // bit pattern that corresponds to type's byte usage
  const char *syntax;      // constant string representation of the type
} G4_Type_Info;

constexpr G4_Type_Info G4_Type_Table[Type_UNDEF + 1]{
    {Type_UD, 32, 4, 0x0F, "ud"},
    {Type_D, 32, 4, 0x0F, "d"},
    {Type_UW, 16, 2, 0x03, "uw"},
    {Type_W, 16, 2, 0x03, "w"},
    {Type_UB, 8, 1, 0x01, "ub"},
    {Type_B, 8, 1, 0x01, "b"},
    {Type_F, 32, 4, 0x0F, "f"},
    {Type_VF, 32, 4, 0x0F, "vf"}, // handle as F?
    {Type_V, 32, 4, 0x0F, "v"},   // handle as D?
    {Type_DF, 64, 8, 0xFF, "df"},
    {Type_BOOL, 1, 2, 0x01, "bool"}, // TODO: how to decide 1 bit here?
    {Type_UV, 32, 4, 0x0F, "uv"},
    {Type_Q, 64, 8, 0xFF, "q"},
    {Type_UQ, 64, 8, 0xFF, "uq"},
    {Type_HF, 16, 2, 0x03, "hf"},
    {Type_NF, 64, 8, 0xFF, "nf"},
    {Type_BF, 16, 2, 0x03, "bf"},
    {Type_UNDEF, 0, 0, 0x0, "???"}};
static inline constexpr G4_Type_Info TypeInfo(G4_Type t) {
  return G4_Type_Table[(unsigned)t > (unsigned)Type_UNDEF ? Type_UNDEF : t];
}
static inline constexpr unsigned short TypeSize(G4_Type t) {
  return TypeInfo(t).byteSize;
}
static inline constexpr unsigned short TypeBitSize(G4_Type t) {
  // TODO: can we use TypeBitSize/8 here? Need to determine why bool is 2 B
  return TypeInfo(t).bitSize;
}
static inline constexpr unsigned short TypeFootprint(G4_Type t) {
  return TypeInfo(t).footprint;
}
static inline constexpr const char *TypeSymbol(G4_Type t) {
  return TypeInfo(t).syntax;
}

enum G4_InstType {
  InstTypeMov = 0,     // mov or sel
  InstTypeLogic,       // not, and, or, xor, ...
  InstTypeCompare,     // cmp, cmpn
  InstTypeFlow,        // if, iff, do, while, break, ...
  InstTypeArith,       // add, mul, frc, mac , ...
  InstTypeVector,      // sad, sad2, dp4, dp3, dp2, ..
  InstTypeMisc,        // send, wait, nop, illegal
  InstTypePseudoLogic, // Pseudo_not, Pseudo_and, ...
  InstTypeReserved     // reserved (unused)
};

enum G4_RegFileKind : unsigned char {
  G4_UndefinedRF = 0x0,
  G4_GRF = 0x1,     // general register file
  G4_ADDRESS = 0x2, // architectural register file
  G4_INPUT = 0x4,   // input payload register
  G4_FLAG = 0x20,
  G4_SCALAR = 0x40,
};

//
// multiple options can coexist so we define one bit for each option
//
enum G4_InstOption {
  InstOpt_NoOpt = 0x0,
  InstOpt_Align16 = 0x00000002,
  InstOpt_M0 = 0x00100000,
  InstOpt_M4 = 0x00200000,
  InstOpt_M8 = 0x00400000,
  InstOpt_M12 = 0x00800000,
  InstOpt_M16 = 0x01000000,
  InstOpt_M20 = 0x02000000,
  InstOpt_M24 = 0x04000000,
  InstOpt_M28 = 0x08000000,
  InstOpt_Switch = 0x00000010,
  InstOpt_Atomic = 0x00000020,
  InstOpt_NoDDChk = 0x00000040,
  InstOpt_NoDDClr = 0x00000080,
  InstOpt_WriteEnable = 0x00000100,

  InstOpt_BreakPoint = 0x00000200,
  InstOpt_EOT = 0x00000400,
  InstOpt_AccWrCtrl = 0x00000800,
  InstOpt_NoCompact = 0x00001000,
  InstOpt_Compacted = 0x00002000,
  InstOpt_NoSrcDepSet = 0x00004000,
  InstOpt_NoPreempt = 0x00008000,
  InstOpt_Serialize = 0x00010000,
  InstOpt_CachelineAligned = 0x00040000,

  InstOpt_END = 0xFFFFFFFF
};

#define InstOpt_QuarterMasks                                                   \
  (InstOpt_M0 | InstOpt_M4 | InstOpt_M8 | InstOpt_M12 | InstOpt_M16 |          \
   InstOpt_M20 | InstOpt_M24 | InstOpt_M28)
#define InstOpt_Masks (InstOpt_QuarterMasks | InstOpt_WriteEnable)

// TODO: to a more proper data type
// ==> step 1: use uint32_t so all the untyped uses still compile
//             but replace all uint32_t (and other int types with G4_InstOpts)
//     step 2: make G4_InstOpts a typesafe enum;
//             #define old unscoped enum names to new typesafe enum
//             (define various set operators so |, &, and ~ still work)
//             remove the few magic number uses with valid type enumes
//     step 3: mechanically (find and replace) old unscoped enums with
//             typesafe symbols and remove #defines
using G4_InstOpts = uint32_t;

typedef struct _G4_InstOptInfo {
  G4_InstOption optMask;
  const char *optStr;
} G4_InstOptInfo;

// various attributes for the Gen opcodes
#define ATTR_NONE 0x00000000
#define ATTR_PSEUDO 0x00000001
#define ATTR_COMMUTATIVE 0x00000002
#define ATTR_FLOAT_SRC_ONLY 0x00000004
#define ATTR_WIDE_DST 0x00000008

#define INST_PSEUDO(inst) (G4_Inst_Table[inst].attributes & ATTR_PSEUDO)
#define INST_COMMUTATIVE(inst)                                                 \
  (G4_Inst_Table[inst].attributes & ATTR_COMMUTATIVE)
#define INST_FLOAT_SRC_ONLY(inst)                                              \
  (G4_Inst_Table[inst].attributes & ATTR_FLOAT_SRC_ONLY)
#define INST_WIDE_DST(inst) (G4_Inst_Table[inst].attributes & ATTR_WIDE_DST)

#define HANDLE_INST(op, nsrc, ndst, type, plat, attr) G4_##op,

enum G4_opcode {
#include "G4_Instruction.h"
  G4_NUM_OPCODE
};

typedef struct _G4_Inst_Info {
  G4_opcode op;             // just for debugging purpose
  const char *str;          // for emitting asm code
  uint8_t n_srcs;           // # of source operands
  uint8_t n_dst;            // # of dst operands
  G4_InstType instType;     // inst classification
  TARGET_PLATFORM platform; // The platform that first supports this inst.
  int attributes;
} G4_Inst_Info;

// ToDo: make this into G4_INST so that not everyone and their grandma are
// directly reading it
extern const G4_Inst_Info G4_Inst_Table[G4_NUM_OPCODE + 1];

// Relation between two regions. The comparison is based on memory locations
// regions reference, which are described by the left-bound, the right bound,
// and their footprint vectors. The exact order of elements or type are not
// considered. For example, region comparison algorithm will return Rel_eq for
// the following region pairs:
//
// * (8) V(0,0)<1>:d and (8) V(0,0)<1;4,2>:d
// * (8) V(0,0)<1>:d and (16) V(0,0)<1;1,0>:w
// * (8) V(0,0)<1>:d and (16) V(0,0)<0;8,1>:d
//
enum G4_CmpRelation {
  Rel_eq = 0,    // region A is the same as region B
  Rel_lt,        // region A is a subset of region B
  Rel_gt,        // region A is a super set of region B
  Rel_interfere, // region A overlaps with region B
  Rel_disjoint,  // region A and region B are disjoint
  Rel_undef      // region A and region B have different base variable
};

#define OPND_NUM_ENUM(DO)                                                      \
  DO(Opnd_dst)                                                                 \
  DO(Opnd_src0)                                                                \
  DO(Opnd_src1)                                                                \
  DO(Opnd_src2)                                                                \
  DO(Opnd_src3)                                                                \
  DO(Opnd_src4)                                                                \
  DO(Opnd_src5)                                                                \
  DO(Opnd_src6)                                                                \
  DO(Opnd_src7)                                                                \
  DO(Opnd_pred)                                                                \
  DO(Opnd_condMod)                                                             \
  DO(Opnd_implAccSrc)                                                          \
  DO(Opnd_implAccDst)                                                          \
  DO(Opnd_total_num)

enum Gen4_Operand_Number : unsigned char { OPND_NUM_ENUM(MAKE_ENUM) };

enum G4_ArchRegKind {
  // Note that the enum values are different from HW values,
  // as we represent acc0 and acc1 as different AReg for example
  AREG_NULL = 0, // null register
  AREG_A0,       // address register
  AREG_ACC0,     // accumulator register
  AREG_ACC1,     // accumulator register
  AREG_MASK0,    // mask register
  AREG_MSG0,     // message control register
  AREG_DBG,      // mask stack depth register
  AREG_SR0,      // state register
  AREG_CR0,      // control register
  AREG_N0,       // notification count register
  AREG_N1,       // notification count register
  AREG_IP,       // instruction pointer register
  AREG_F0,       // flag register
  AREG_F1,       // flag register
  AREG_TM0,      // timestamp register
  AREG_TDR0,     // TDR register
  AREG_SP,       // SP register
  AREG_F2,       // flag register (PVC+)
  AREG_F3,       // flag register (PVC+)
  AREG_S0,       // scalar register
  AREG_LAST
};

enum G4_AccRegSel : unsigned char {
  ACC2 = 0,
  ACC3,
  ACC4,
  ACC5,
  ACC6,
  ACC7,
  ACC8,
  ACC9,
  NOACC,
  ACC_UNDEFINED = 0xff
};

// global functions
uint8_t roundDownPow2(uint8_t n);

// G4_type related global functions
inline bool isLowPrecisionFloatTy(G4_Type ty) {
  return ty == Type_HF || ty == Type_BF;
}

inline G4_Type floatToSameWidthIntType(G4_Type floatTy) {
  vASSERT(IS_TYPE_FLOAT_ALL(floatTy));
  switch (TypeSize(floatTy)) {
  case 1:
    return Type_UB;
  case 2:
    return Type_UW;
  case 4:
    return Type_UD;
  case 8:
    return Type_UQ;
  default:
    vISA_ASSERT_UNREACHABLE("illegal type size");
    return Type_UD;
  }
}

// size is the number of byte
inline G4_SubReg_Align Get_G4_SubRegAlign_From_Size(uint16_t size,
                                                    TARGET_PLATFORM platform,
                                                    G4_SubReg_Align GRFAlign) {
  switch (size) {
  case 1:
  case 2:
    return Any;
  case 4:
    return Even_Word;
  case 8:
    if (platform != GENX_BXT)
      return Four_Word;
    // FALL THROUGH
    // WA: It's a workaround where a potential HW issue needs
    // identifying.
  case 16:
    return Eight_Word;
  case 32:
    return Sixteen_Word;
  case 64:
    return ThirtyTwo_Word;
  default:
    return GRFAlign;
  }
}

inline G4_SubReg_Align Get_G4_SubRegAlign_From_Type(G4_Type ty) {
  switch (ty) {
  case Type_B:
  case Type_UB:
  case Type_W:
  case Type_UW:
    return Any;
  case Type_UD:
  case Type_D:
  case Type_F:
    return Even_Word;
  case Type_DF:
    return Four_Word;
  case Type_V:
  case Type_VF:
  case Type_UV:
    return Eight_Word;
  case Type_Q:
  case Type_UQ:
    return Four_Word;
  default:
    return Any;
  }
}
#endif // _G4_OPCODE_H_