• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2014 Intel Corporation
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21  * IN THE SOFTWARE.
22  */
23 
24 #include "elk_cfg.h"
25 #include "elk_eu.h"
26 #include "elk_disasm.h"
27 #include "elk_disasm_info.h"
28 #include "dev/intel_debug.h"
29 #include "compiler/nir/nir.h"
30 
nir_print_instr(UNUSED const nir_instr * instr,UNUSED FILE * fp)31 __attribute__((weak)) void nir_print_instr(UNUSED const nir_instr *instr,
32                                            UNUSED FILE *fp) {}
33 
34 void
elk_dump_assembly(void * assembly,int start_offset,int end_offset,struct elk_disasm_info * disasm,const unsigned * block_latency)35 elk_dump_assembly(void *assembly, int start_offset, int end_offset,
36               struct elk_disasm_info *disasm, const unsigned *block_latency)
37 {
38    const struct elk_isa_info *isa = disasm->isa;
39    const char *last_annotation_string = NULL;
40    const void *last_annotation_ir = NULL;
41 
42    void *mem_ctx = ralloc_context(NULL);
43    const struct elk_label *root_label =
44       elk_label_assembly(isa, assembly, start_offset, end_offset, mem_ctx);
45 
46    foreach_list_typed(struct inst_group, group, link, &disasm->group_list) {
47       struct exec_node *next_node = exec_node_get_next(&group->link);
48       if (exec_node_is_tail_sentinel(next_node))
49          break;
50 
51       struct inst_group *next =
52          exec_node_data(struct inst_group, next_node, link);
53 
54       int start_offset = group->offset;
55       int end_offset = next->offset;
56 
57       if (group->block_start) {
58          fprintf(stderr, "   START B%d", group->block_start->num);
59          foreach_list_typed(struct elk_bblock_link, predecessor_link, link,
60                             &group->block_start->parents) {
61             struct elk_bblock_t *predecessor_block = predecessor_link->block;
62             fprintf(stderr, " <-B%d", predecessor_block->num);
63          }
64          if (block_latency)
65             fprintf(stderr, " (%u cycles)",
66                     block_latency[group->block_start->num]);
67          fprintf(stderr, "\n");
68       }
69 
70       if (last_annotation_ir != group->ir) {
71          last_annotation_ir = group->ir;
72          if (last_annotation_ir) {
73             fprintf(stderr, "   ");
74             nir_print_instr(group->ir, stderr);
75             fprintf(stderr, "\n");
76          }
77       }
78 
79       if (last_annotation_string != group->annotation) {
80          last_annotation_string = group->annotation;
81          if (last_annotation_string)
82             fprintf(stderr, "   %s\n", last_annotation_string);
83       }
84 
85       elk_disassemble(isa, assembly, start_offset, end_offset,
86                       root_label, stderr);
87 
88       if (group->error) {
89          fputs(group->error, stderr);
90       }
91 
92       if (group->block_end) {
93          fprintf(stderr, "   END B%d", group->block_end->num);
94          foreach_list_typed(struct elk_bblock_link, successor_link, link,
95                             &group->block_end->children) {
96             struct elk_bblock_t *successor_block = successor_link->block;
97             fprintf(stderr, " ->B%d", successor_block->num);
98          }
99          fprintf(stderr, "\n");
100       }
101    }
102    fprintf(stderr, "\n");
103 
104    ralloc_free(mem_ctx);
105 }
106 
107 struct elk_disasm_info *
elk_disasm_initialize(const struct elk_isa_info * isa,const struct elk_cfg_t * cfg)108 elk_disasm_initialize(const struct elk_isa_info *isa,
109                   const struct elk_cfg_t *cfg)
110 {
111    struct elk_disasm_info *disasm = ralloc(NULL, struct elk_disasm_info);
112    exec_list_make_empty(&disasm->group_list);
113    disasm->isa = isa;
114    disasm->cfg = cfg;
115    disasm->cur_block = 0;
116    disasm->use_tail = false;
117    return disasm;
118 }
119 
120 struct inst_group *
elk_disasm_new_inst_group(struct elk_disasm_info * disasm,unsigned next_inst_offset)121 elk_disasm_new_inst_group(struct elk_disasm_info *disasm, unsigned next_inst_offset)
122 {
123    struct inst_group *tail = rzalloc(disasm, struct inst_group);
124    tail->offset = next_inst_offset;
125    exec_list_push_tail(&disasm->group_list, &tail->link);
126    return tail;
127 }
128 
129 void
elk_disasm_annotate(struct elk_disasm_info * disasm,struct elk_backend_instruction * inst,unsigned offset)130 elk_disasm_annotate(struct elk_disasm_info *disasm,
131                 struct elk_backend_instruction *inst, unsigned offset)
132 {
133    const struct intel_device_info *devinfo = disasm->isa->devinfo;
134    const struct elk_cfg_t *cfg = disasm->cfg;
135 
136    struct inst_group *group;
137    if (!disasm->use_tail) {
138       group = elk_disasm_new_inst_group(disasm, offset);
139    } else {
140       disasm->use_tail = false;
141       group = exec_node_data(struct inst_group,
142                              exec_list_get_tail_raw(&disasm->group_list), link);
143    }
144 
145    if (INTEL_DEBUG(DEBUG_ANNOTATION)) {
146       group->ir = inst->ir;
147       group->annotation = inst->annotation;
148    }
149 
150    if (bblock_start(cfg->blocks[disasm->cur_block]) == inst) {
151       group->block_start = cfg->blocks[disasm->cur_block];
152    }
153 
154    /* There is no hardware DO instruction on Gfx6+, so since DO always
155     * starts a basic block, we need to set the .block_start of the next
156     * instruction's annotation with a pointer to the bblock started by
157     * the DO.
158     *
159     * There's also only complication from emitting an annotation without
160     * a corresponding hardware instruction to disassemble.
161     */
162    if (devinfo->ver >= 6 && inst->opcode == ELK_OPCODE_DO) {
163       disasm->use_tail = true;
164    }
165 
166    if (bblock_end(cfg->blocks[disasm->cur_block]) == inst) {
167       group->block_end = cfg->blocks[disasm->cur_block];
168       disasm->cur_block++;
169    }
170 }
171 
172 void
elk_disasm_insert_error(struct elk_disasm_info * disasm,unsigned offset,unsigned inst_size,const char * error)173 elk_disasm_insert_error(struct elk_disasm_info *disasm, unsigned offset,
174                     unsigned inst_size, const char *error)
175 {
176    foreach_list_typed(struct inst_group, cur, link, &disasm->group_list) {
177       struct exec_node *next_node = exec_node_get_next(&cur->link);
178       if (exec_node_is_tail_sentinel(next_node))
179          break;
180 
181       struct inst_group *next =
182          exec_node_data(struct inst_group, next_node, link);
183 
184       if (next->offset <= offset)
185          continue;
186 
187       if (offset + inst_size != next->offset) {
188          struct inst_group *new = ralloc(disasm, struct inst_group);
189          memcpy(new, cur, sizeof(struct inst_group));
190 
191          cur->error = NULL;
192          cur->error_length = 0;
193          cur->block_end = NULL;
194 
195          new->offset = offset + inst_size;
196          new->block_start = NULL;
197 
198          exec_node_insert_after(&cur->link, &new->link);
199       }
200 
201       if (cur->error)
202          ralloc_strcat(&cur->error, error);
203       else
204          cur->error = ralloc_strdup(disasm, error);
205       return;
206    }
207 }
208