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