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_KV_H
10 #define IGA_KV_H
11 
12 #include "iga.h"
13 #include "iga_types_swsb.hpp"
14 
15 /*************************************************************************
16  *                                                                       *
17  *                  The KernelView C interface                           *
18  *                                                                       *
19  *************************************************************************/
20 
21 #ifdef __cplusplus
22 extern "C"  {
23 #endif
24 
25 /*
26  * This symbols defines the maximum number of PC targets that an instruction
27  * may have.  It is typically used to statically allocate an array of target
28  * PCs with the kv_get_inst_targets function.
29  * E.g.
30  *   uint32_t targetPCs[KV_MAX_TARGETS_PER_INSTRUCTION];
31  *   uint32_t num = kv_get_inst_targets(kv, atPc, &targets[0]);
32  *   for (int i = 0; i < num; i++) {
33  *      processTarget(targetPCs[i]);
34  *   }
35  */
36 #define KV_MAX_TARGETS_PER_INSTRUCTION 3
37 /*
38 * This symbol represents an invalid PC.  0 is a valid PC (the beginnning
39 * of the kernel).
40 */
41 #define KV_INVALID_PC_VALUE ((int32_t)0xFFFFFFFF)
42 
43 /* incomplete type for a kernel view handle */
44 struct kv_t;
45 
46 /* Kernel viewer statuses */
47 typedef enum {
48     KV_SUCCESS          = 0,
49     KV_ERROR            = 1, /* general error */
50     KV_DECODE_ERROR     = 2, /*
51                               * error during initial decode of the kernel
52                               * always check KernelView::decodeSucceeded.
53                               */
54     KV_INVALID_PC       = 3,  /* invalid instruction PC */
55 
56     KV_INVALID_ARGUMENT = 10, /* an invalid argument passed in */
57 
58     KV_NON_SEND_INSTRUCTION   = 20, /* underlying inst isn't a send */
59     KV_DESCRIPTOR_INDIRECT    = 21, /* a send message with a reg desc */
60     KV_DESCRIPTOR_INVALID     = 22, /* an unrecognized send descriptor */
61     KV_NO_SUBFUNCTION         = 23, /* underlying inst has no sub-function */
62 
63     KV_INCAPABLE_PLATFORM     = 30  /* the called-api is incapable on the platform*/
64 } kv_status_t;
65 
66 /*
67  * Creates a kernel view.
68  *   'plat' - the platform
69  *   'bytes' - the kernel binary
70  *   'bytes_len' - the length of 'bytes'
71  *   'status' - the IGA status code
72  *   'errbuf' - an optional buffer to emit errors or warnings (can pass nullptr)
73  *   'errbuf_cap' - the capacity of errbuf.
74  * RETURNS: a kernel view object for use in other kv_* functions.
75  *  Deallocate it with kv_delete.  If there is a decode error (or other errors), this
76  *  function returns an instance of Kernel Views and ERROR status. If user proceeds
77  * to use the returned Kernel View we do not guarantee that all bits are correct
78  */
79 IGA_API kv_t *kv_create(
80     iga_gen_t plat,
81     const void *bytes,
82     size_t bytes_len,
83     iga_status_t *status,
84     char *errbuf,
85     size_t errbuf_cap,
86     // if not specified, the swsb encoding mode will be derived from platfrom
87     // by SWSB::getEncodeMode
88     iga::SWSB_ENCODE_MODE swsb_enc_mode
89         = iga::SWSB_ENCODE_MODE::SWSBInvalidMode
90     );
91 
92 /* destroys a kernel view */
93 IGA_API void kv_delete(kv_t *);
94 
95 
96 /*
97 * Returns the size of the instruction at 'pc'; returns 0 if the program
98 * address is out of bounds.  This allows one to iterate a kernel using this
99 * API.  For example:
100 *
101 *   uint32_t iLen;
102 *   for (uint32_t pc = 0;
103 *        (iLen = kv_get_inst_size(kv, pc)) != 0;
104 *        pc += iLen)
105 *   {
106 *     ... process instruction
107 *   }
108 */
109 IGA_API int32_t kv_get_inst_size(const kv_t *kv, int32_t pc);
110 
111 /*
112 * Returns true if the instruction has the opt
113 */
114 IGA_API bool kv_has_inst_opt(const kv_t *kv, int32_t pc, uint32_t opt);
115 
116 /*
117 * This function returns the absolute PC targets of this instruction.
118 * For branching instructions, it populates 'pcs' with the jump targets
119 * of this instruction.  The number of PC's will always be less than or
120 * equal to MAX_KV_TARGETS_COUNT.  The function returns the number of
121 * target PCs populated in the 'pcs' argument.
122 *
123 * For non-branching instructions this returns 0 and does not touch 'pcs'.
124 *
125 * If 'pcs' is NULL, it is ignored.  The number of targets is still returned.
126 */
127 IGA_API uint32_t kv_get_inst_targets(
128     const kv_t *kv,
129     int32_t pc,
130     int32_t *pcs);
131 
132 
133 /*
134  * This function returns the syntax for a given instruction.
135  * The user passes the buffer 'sbuf' (along with its capacity) to hold
136  * the output.  The output may be truncated if the passed buffer is too
137  * small, but it will always be suffixed with a NUL byte.
138  *
139  * The formatting options 'fmt_opts' are the same as those in
140  * iga_disassemble_options_t::formatting_opts.
141  *
142  * The optional 'get_label_name' callback may be called to converts
143  * a PC into a label.  The caller can provide NULL and internal label names
144  * will be used.  The 'env' context parameter is passed to 'get_label_name'.
145  * Memory returned by the callback is only read by IGA.
146  *
147  * This function returns the number of characters written to sbuf
148  * (including NUL byte).  If the PC is out of bounds or 'kv' NULL or
149  * something else is wrong, then 0 is returned.
150  */
151 IGA_API size_t kv_get_inst_syntax(
152     const kv_t *kv,
153     int32_t pc,
154     char *sbuf,
155     size_t sbuf_cap,
156     uint32_t fmt_opts,
157     const char *(*get_label_name)(int32_t, void *),
158     void *env);
159 
160 /*
161  * This function returns the default label name if custom labeler is not used.
162  */
163 IGA_API size_t kv_get_default_label_name(
164     int32_t pc,
165     char *sbuf,
166     size_t sbuf_cap);
167 
168 /*
169  * Returns non-zero iff this instruction is a branch target.
170  * The caller can use this function to determine if it should emit a label
171  * first.
172  */
173 IGA_API uint32_t kv_is_inst_target(const kv_t *kv, int32_t pc);
174 
175 
176 /*
177  * This enumeration allows one to determine if a given PC is for structured
178  * control flow.  This is for tools that want to render an indentation for
179  * readability.
180  */
181 typedef enum {
182     KV_OPGROUP_INVALID,   /* not a valid op (e.g. out of bounds, middle of instruction) */
183     KV_OPGROUP_OTHER,     /* some other instruction */
184     KV_OPGROUP_IF,        /* an 'if' op */
185     KV_OPGROUP_ELSE,      /* an 'else' op */
186     KV_OPGROUP_ENDIF,     /* an 'endif' op */
187     KV_OPGROUP_WHILE,     /* a 'while' op */
188     KV_OPGROUP_SEND_EOT,  /* a send message with the EOT bit set */
189 } kv_opgroup_t;
190 
191 
192 /*
193  * This function returns the opcode group.  The result may be compared
194  * to the integral value of the various kv_opcode_group enumerates.
195  * (See enum kv_get_opgroup_t.)
196  */
197 IGA_API int32_t kv_get_opgroup(const kv_t *kv, int32_t pc);
198 
199 
200 /*
201  * Returns the send function descriptors.  The count of descriptors is
202  * returned; hence, if the instruction is invalid or not a send or
203  * send using two index registers, 0 is returned.
204  * If one of the descriptors is not immediate, then 1 is returned
205  * and that descriptor is set to KV_INVALID_SEND_DESC.
206  *
207  * Also returns 0 if any parameter is NULL (and parameters are untouched).
208  */
209 IGA_API uint32_t kv_get_send_descs(
210     const kv_t *kv,
211     int32_t pc,
212     uint32_t *ex_desc,
213     uint32_t *desc);
214 
215 
216 /*
217  * Returns the indirect descriptor registers for a send message.
218  * The function fails silently if the PC is invalid or a nullptr is passed.
219  * Registers are assigned KV_INVALID_REG on other failures otherwise they
220  * hold the index register and subregister (e.g. a0.2) would have 0 and 2.
221  */
222 IGA_API void kv_get_send_indirect_descs(
223     const kv_t *kv,
224     int32_t pc,
225     uint8_t *ex_desc_reg,
226     uint8_t *ex_desc_subreg,
227     uint8_t *desc_reg,
228     uint8_t *desc_subreg);
229 
230 /*
231 * Determines if the given send instruction is on ExBSO mode.
232 * exbso = 1 if true, 0 if fales.
233 * exbso = -1 if not success.
234 * exbso mode is introduces since XeHP.
235 *
236 * RETURNS:
237 *  KV_SUCCESS               on success
238 *  KV_NON_SEND_INSTRUCTION  if called on a non-send instruction
239 *  KV_INVALID_PC            if passed an invalid PC
240 *  KV_INVALID_ARGUMENT      if given a null parameter
241 *  KV_INCAPABLE_PLATFORM    if it's not XeHP+ platform
242 */
243 IGA_API kv_status_t kv_get_send_exbso(
244     const kv_t *kv,
245     int32_t pc,
246     int32_t *exbso);
247 
248 /*
249  * A symbol to indicate an invalid send descriptor value.
250  */
251 #define KV_INVALID_SEND_DESC ((uint32_t)0xFFFFFFFFF)
252 
253 /* TODO: review necessity of this macro.
254  * A symbol to indicate an invalid message length value.
255  */
256 #define KV_INVALID_LEN ((uint32_t)0xFFFFFFFFF)
257 
258 /*
259  * Indicates invalid register
260  */
261 #define KV_INVALID_REG 0xff
262 
263 /*
264  * Determines the message type for the given send instruction.
265  * The result is returned via the pointer 'message_type_enum' - an
266  * iga::SFMessageType value.
267  *
268  * RETURNS:
269  *  KV_SUCCESS               on success
270  *  KV_NON_SEND_INSTRUCTION  if called on a non-send instruction
271  *  KV_DESCRIPTOR_INDIRECT   if called on a send with reg descriptors
272  *  KV_DESCRIPTOR_INVALID    if unable to map the descriptor value
273  *                           (not all messages are mapped via this API)
274  *  KV_INVALID_PC            if passed an invalid PC
275  *  KV_INVALID_ARGUMENT      if given a null parameter
276  */
277 IGA_API kv_status_t kv_get_message_type(
278     const kv_t *kv, int32_t pc, int32_t *message_type_enum);
279 
280 /*
281  * Determines the message type for the given send instruction.
282  * desc and sfid are passed in explicitly when indirect desc prevents
283  * use of kv_get_message_type.
284  * The result is returned via the pointer 'message_type_enum' - an
285  * iga::SFMessageType value.
286  *
287  * RETURNS:
288  *  KV_SUCCESS               on success
289  *  KV_NON_SEND_INSTRUCTION  if called on a non-send instruction
290  *  KV_DESCRIPTOR_INDIRECT   if called on a send with reg descriptors
291  *  KV_DESCRIPTOR_INVALID    if unable to map the descriptor value
292  *                           (not all messages are mapped via this API)
293  *  KV_INVALID_PC            if passed an invalid PC
294  *  KV_INVALID_ARGUMENT      if given a null parameter
295  */
296 IGA_API kv_status_t kv_get_message_type_ext(
297     const kv_t *kv, int32_t pc, uint32_t desc, int32_t sfid, int32_t *message_type_enum);
298 
299 /*
300  * Determines the message sfid for the given send instruction.
301  * The result is returned via the pointer 'sfid_enum' - an iga::SFID
302  *
303  * RETURNS:
304  *  KV_SUCCESS               on success
305  *  KV_NON_SEND_INSTRUCTION  if called on a non-send instruction
306  *  KV_DESCRIPTOR_INDIRECT   if called on a send with reg descriptors
307  *  KV_DESCRIPTOR_INVALID    if unable to map the descriptor value
308  *  KV_INVALID_PC            if passed an invalid PC
309  *  KV_INVALID_ARGUMENT      if given a null parameter
310  */
311 IGA_API kv_status_t kv_get_message_sfid(
312     const kv_t *kv, int32_t pc, int32_t *sfid_enum);
313 
314 /*
315  * Gets message length, extended message length, and response length in
316  * units of registers.  The count of lengths successfully set is returned.
317  * If any of the parameters is NULL, it returns 0.  Invalid lengths are set
318  * to KV_INVALID_LEN.
319  */
320 IGA_API uint32_t kv_get_message_len(
321     const kv_t *kv, int32_t pc, uint32_t* mLen, uint32_t* emLen, uint32_t* rLen);
322 
323 /*
324  * Alternative version of kv_get_message_len when desc or exDesc are
325  * indirect.  If any of the parameters is NULL, it returns 0.  Invalid lengths
326  * are set to KV_INVALID_LEN.
327  */
328 IGA_API uint32_t kv_get_message_len_ext(
329     const kv_t *kv, int32_t pc, uint32_t desc, uint32_t exDesc,
330     uint32_t* mLen, uint32_t* emLen, uint32_t* rLen);
331 
332 /*
333  * Returns the ExecSize of the instruction (SIMD width)
334  * 0 - INVALID
335  * 1 - EXEC_SIZE_1
336  * 2 - EXEC_SIZE_2
337  * 3 - EXEC_SIZE_4
338  * 4 - EXEC_SIZE_8
339  * 5 - EXEC_SIZE_16
340  * 6 - EXEC_SIZE_32
341  */
342 IGA_API uint32_t kv_get_execution_size(const kv_t *kv, int32_t pc);
343 
344 /*
345  * Returns Software scoreboarding information.
346  */
347 IGA_API bool kv_get_swsb_info(
348     const kv_t *kv, int32_t pc, iga::SWSB_ENCODE_MODE encdoe_mode,
349     iga::SWSB& swsb);
350 
351 /*
352  * Returns number of sources this instruction has.
353  */
354 IGA_API int32_t kv_get_number_sources(const kv_t *kv, int32_t pc);
355 
356 /*
357  * This function returns OPcode integer.  The value corresponds to
358  * binary encoding value of the opcode.
359  */
360 IGA_API uint32_t kv_get_opcode(const kv_t *kv, int32_t pc);
361 
362 /*
363  * This function returns OPcode integer.  The value corresponds to
364  * binary encoding value of the opcode.
365  */
366 IGA_API kv_status_t kv_get_subfunction(const kv_t *kv, int32_t pc, uint32_t* subfunc);
367 
368 /*
369  * This function returns if intruction has destination.
370  */
371 IGA_API int32_t kv_get_has_destination(const kv_t *kv, int32_t pc);
372 
373 /*
374  * This function returns destination Register row
375  */
376 IGA_API int32_t kv_get_destination_register(const kv_t *kv, int32_t pc);
377 
378 /*
379  * This function returns destination subRegister
380  */
381 IGA_API int32_t kv_get_destination_sub_register(const kv_t *kv, int32_t pc);
382 
383 /*
384  * This function returns destination data type
385  * i.e. F, HF, INT, etc
386  */
387 IGA_API uint32_t kv_get_destination_data_type(const kv_t *kv, int32_t pc);
388 
389 /*
390  * This function returns destination register type
391  * i.e. GRF, various ARF registers
392  */
393 IGA_API uint32_t kv_get_destination_register_type(const kv_t *kv, int32_t pc);
394 
395 /*
396  * This function returns destination register KIND
397  * DIRECT, INDIRECT, IMM, INDIR etc
398  */
399 IGA_API uint32_t kv_get_destination_register_kind(const kv_t *kv, int32_t pc);
400 
401 /*
402  * This function returns source register line number for a given source.
403  */
404 IGA_API int32_t kv_get_source_register(const kv_t *kv, int32_t pc, uint32_t sourceNumber);
405 
406 /*
407  * This function returns source subRegister for a given source.
408  */
409 IGA_API int32_t kv_get_source_sub_register(const kv_t *kv, int32_t pc, uint32_t sourceNumber);
410 
411 /*
412  * This function returns source data type for a given source
413  * i.e. F, HF, INT, etc
414  */
415 IGA_API uint32_t kv_get_source_data_type(const kv_t *kv, int32_t pc, uint32_t sourceNumber);
416 
417 /*
418  * This function returns source register type for a given source.
419  * i.e. GRF, various ARF registers
420  */
421 IGA_API uint32_t kv_get_source_register_type(const kv_t *kv, int32_t pc, uint32_t sourceNumber);
422 
423 /*
424  * This function returns source register KIND for a given source
425  * DIRECT, INDIRECT, IMM, INDIR etc
426  */
427 IGA_API uint32_t kv_get_source_register_kind(const kv_t *kv, int32_t pc, uint32_t sourceNumber);
428 
429 /*
430  * This function returns whether source is a vector.
431  */
432 IGA_API int32_t kv_is_source_vector(const kv_t *kv, int32_t pc, uint32_t sourceNumber);
433 
434 /*
435  * This function returns mask offset
436  */
437 IGA_API uint32_t kv_get_channel_offset(const kv_t *kv, int32_t pc);
438 
439 /*
440  * This function returns mask control
441  */
442 IGA_API uint32_t kv_get_mask_control(const kv_t *kv, int32_t pc);
443 
444 /*
445  * This function exposes destination region.
446  */
447 IGA_API int32_t kv_get_destination_region(
448     const kv_t *kv, int32_t pc, uint32_t *hz);
449 
450 /*
451  * This function exposes source operand region.
452  */
453 IGA_API int32_t kv_get_source_region(
454     const kv_t *kv, int32_t pc, uint32_t src_op,
455     uint32_t *vt, uint32_t *wi, uint32_t *hz);
456 
457 /*
458  * This function exposes source operand immediate value.
459  */
460 IGA_API int32_t kv_get_source_immediate(
461     const kv_t *kv, int32_t pc, uint32_t src_op, uint64_t *imm);
462 
463 /*
464  * This function exposes indirect source's immediate offset.
465    Return -1 if given source is not indirect srouce
466  */
467 IGA_API int32_t kv_get_source_indirect_imm_off(
468     const kv_t *kv, int32_t pc, uint32_t src_op, int16_t *immoff);
469 
470 /*
471  * This function exposes indirect destination's immediate offset.
472    Return -1 if given destination is not indirect srouce
473  */
474 IGA_API int32_t kv_get_destination_indirect_imm_off(
475     const kv_t *kv, int32_t pc, int16_t *mme);
476 
477 /*
478  * This function exposes source's MathMacroExt number for
479    math macro instructions.
480    mme is the mme numbar, set to 8 if it's nomme.
481    Return 0 if the given instruction is math macro instruction.
482    Return -1 if given instruction is not math macro instruction.
483  */
484 IGA_API int32_t kv_get_source_mme_number(
485     const kv_t *kv, int32_t pc, uint32_t src_op, int16_t *mme);
486 
487 /*
488  * This function exposes destination's MathMacroExt number for
489    math macro instructions.
490    mme is the mme numbar, set to 8 if it's nomme.
491    Return 0 if the given instruction is math macro instruction.
492    Return -1 if given instruction is not math macro instruction.
493  */
494 IGA_API int32_t kv_get_destination_mme_number(
495     const kv_t *kv, int32_t pc, int16_t *immoff);
496 
497 /*
498  * This function return flag modifier (FlagModifier)
499  */
500 IGA_API uint32_t kv_get_flag_modifier(const kv_t *kv, int32_t pc);
501 
502 /*
503  * This function return source modifier
504  * This returns a SrcModifier
505  */
506 IGA_API uint32_t kv_get_source_modifier(
507     const kv_t *kv, int32_t pc, uint32_t src_op);
508 
509 /*
510  * This function return destination modifier
511  * This returns a DstModifier
512  */
513 IGA_API uint32_t kv_get_destination_modifier(const kv_t *kv, int32_t pc);
514 
515 /*
516  * This function return the flag register
517  */
518 IGA_API int32_t kv_get_flag_register(const kv_t *kv, int32_t pc);
519 
520 /*
521  * This function return the flag sub register
522  */
523 IGA_API int32_t kv_get_flag_sub_register(const kv_t *kv, int32_t pc);
524 
525 /*
526  * This function return the flag predicate function (a PredCtrl)
527  */
528 IGA_API uint32_t kv_get_predicate(const kv_t *kv, int32_t pc);
529 
530 /*
531  * This function returns the logical sign on the predicate (inverted or not)
532  */
533 IGA_API uint32_t kv_get_is_inverse_predicate(const kv_t *kv, int32_t pc);
534 
535 
536 
537 #ifdef __cplusplus
538 }
539 #endif
540 #endif
541