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