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 "brw_cfg.h"
25 #include "brw_eu.h"
26 #include "brw_disasm_info.h"
27 #include "dev/intel_debug.h"
28 #include "compiler/nir/nir.h"
29 
nir_print_instr(UNUSED const nir_instr * instr,UNUSED FILE * fp)30 __attribute__((weak)) void nir_print_instr(UNUSED const nir_instr *instr,
31                                            UNUSED FILE *fp) {}
32 
33 void
dump_assembly(void * assembly,int start_offset,int end_offset,struct disasm_info * disasm,const unsigned * block_latency)34 dump_assembly(void *assembly, int start_offset, int end_offset,
35               struct disasm_info *disasm, const unsigned *block_latency)
36 {
37    const struct intel_device_info *devinfo = disasm->devinfo;
38    const char *last_annotation_string = NULL;
39    const void *last_annotation_ir = NULL;
40 
41    void *mem_ctx = ralloc_context(NULL);
42    const struct brw_label *root_label =
43       brw_label_assembly(devinfo, assembly, start_offset, end_offset, mem_ctx);
44 
45    foreach_list_typed(struct inst_group, group, link, &disasm->group_list) {
46       struct exec_node *next_node = exec_node_get_next(&group->link);
47       if (exec_node_is_tail_sentinel(next_node))
48          break;
49 
50       struct inst_group *next =
51          exec_node_data(struct inst_group, next_node, link);
52 
53       int start_offset = group->offset;
54       int end_offset = next->offset;
55 
56       if (group->block_start) {
57          fprintf(stderr, "   START B%d", group->block_start->num);
58          foreach_list_typed(struct bblock_link, predecessor_link, link,
59                             &group->block_start->parents) {
60             struct bblock_t *predecessor_block = predecessor_link->block;
61             fprintf(stderr, " <-B%d", predecessor_block->num);
62          }
63          if (block_latency)
64             fprintf(stderr, " (%u cycles)",
65                     block_latency[group->block_start->num]);
66          fprintf(stderr, "\n");
67       }
68 
69       if (last_annotation_ir != group->ir) {
70          last_annotation_ir = group->ir;
71          if (last_annotation_ir) {
72             fprintf(stderr, "   ");
73             nir_print_instr(group->ir, stderr);
74             fprintf(stderr, "\n");
75          }
76       }
77 
78       if (last_annotation_string != group->annotation) {
79          last_annotation_string = group->annotation;
80          if (last_annotation_string)
81             fprintf(stderr, "   %s\n", last_annotation_string);
82       }
83 
84       brw_disassemble(devinfo, assembly, start_offset, end_offset,
85                       root_label, stderr);
86 
87       if (group->error) {
88          fputs(group->error, stderr);
89       }
90 
91       if (group->block_end) {
92          fprintf(stderr, "   END B%d", group->block_end->num);
93          foreach_list_typed(struct bblock_link, successor_link, link,
94                             &group->block_end->children) {
95             struct bblock_t *successor_block = successor_link->block;
96             fprintf(stderr, " ->B%d", successor_block->num);
97          }
98          fprintf(stderr, "\n");
99       }
100    }
101    fprintf(stderr, "\n");
102 
103    ralloc_free(mem_ctx);
104 }
105 
106 struct disasm_info *
disasm_initialize(const struct intel_device_info * devinfo,const struct cfg_t * cfg)107 disasm_initialize(const struct intel_device_info *devinfo,
108                   const struct cfg_t *cfg)
109 {
110    struct disasm_info *disasm = ralloc(NULL, struct disasm_info);
111    exec_list_make_empty(&disasm->group_list);
112    disasm->devinfo = devinfo;
113    disasm->cfg = cfg;
114    disasm->cur_block = 0;
115    disasm->use_tail = false;
116    return disasm;
117 }
118 
119 struct inst_group *
disasm_new_inst_group(struct disasm_info * disasm,unsigned next_inst_offset)120 disasm_new_inst_group(struct disasm_info *disasm, unsigned next_inst_offset)
121 {
122    struct inst_group *tail = rzalloc(disasm, struct inst_group);
123    tail->offset = next_inst_offset;
124    exec_list_push_tail(&disasm->group_list, &tail->link);
125    return tail;
126 }
127 
128 void
disasm_annotate(struct disasm_info * disasm,struct backend_instruction * inst,unsigned offset)129 disasm_annotate(struct disasm_info *disasm,
130                 struct backend_instruction *inst, unsigned offset)
131 {
132    const struct intel_device_info *devinfo = disasm->devinfo;
133    const struct cfg_t *cfg = disasm->cfg;
134 
135    struct inst_group *group;
136    if (!disasm->use_tail) {
137       group = disasm_new_inst_group(disasm, offset);
138    } else {
139       disasm->use_tail = false;
140       group = exec_node_data(struct inst_group,
141                              exec_list_get_tail_raw(&disasm->group_list), link);
142    }
143 
144    if (INTEL_DEBUG(DEBUG_ANNOTATION)) {
145       group->ir = inst->ir;
146       group->annotation = inst->annotation;
147    }
148 
149    if (bblock_start(cfg->blocks[disasm->cur_block]) == inst) {
150       group->block_start = cfg->blocks[disasm->cur_block];
151    }
152 
153    /* There is no hardware DO instruction on Gfx6+, so since DO always
154     * starts a basic block, we need to set the .block_start of the next
155     * instruction's annotation with a pointer to the bblock started by
156     * the DO.
157     *
158     * There's also only complication from emitting an annotation without
159     * a corresponding hardware instruction to disassemble.
160     */
161    if (devinfo->ver >= 6 && inst->opcode == BRW_OPCODE_DO) {
162       disasm->use_tail = true;
163    }
164 
165    if (bblock_end(cfg->blocks[disasm->cur_block]) == inst) {
166       group->block_end = cfg->blocks[disasm->cur_block];
167       disasm->cur_block++;
168    }
169 }
170 
171 void
disasm_insert_error(struct disasm_info * disasm,unsigned offset,const char * error)172 disasm_insert_error(struct disasm_info *disasm, unsigned offset,
173                     const char *error)
174 {
175    foreach_list_typed(struct inst_group, cur, link, &disasm->group_list) {
176       struct exec_node *next_node = exec_node_get_next(&cur->link);
177       if (exec_node_is_tail_sentinel(next_node))
178          break;
179 
180       struct inst_group *next =
181          exec_node_data(struct inst_group, next_node, link);
182 
183       if (next->offset <= offset)
184          continue;
185 
186       if (offset + sizeof(brw_inst) != next->offset) {
187          struct inst_group *new = ralloc(disasm, struct inst_group);
188          memcpy(new, cur, sizeof(struct inst_group));
189 
190          cur->error = NULL;
191          cur->error_length = 0;
192          cur->block_end = NULL;
193 
194          new->offset = offset + sizeof(brw_inst);
195          new->block_start = NULL;
196 
197          exec_node_insert_after(&cur->link, &new->link);
198       }
199 
200       if (cur->error)
201          ralloc_strcat(&cur->error, error);
202       else
203          cur->error = ralloc_strdup(disasm, error);
204       return;
205    }
206 }
207