mesa/src/intel/compiler/brw/brw_disasm_info.cpp

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

231 lines
6.9 KiB
C++
Raw Normal View History

/*
* Copyright © 2014 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "brw_cfg.h"
#include "brw_eu.h"
#include "brw_disasm.h"
#include "brw_disasm_info.h"
#include "dev/intel_debug.h"
#include "compiler/nir/nir.h"
brw: Fix printing of blocks in disassembly when BRW is available When disassembling and BRW IR is available (which happens in the generator), there will be pointers to the BRW's basic block structures that are used to print the block numbers and predecessor/successors in the output. There are two challenges: - Because DO and FLOW instructions are not real instructions, they are not emitted in the output but would still cause the output to contain empty blocks. Previous code accounted for DO but still had problems. - DO blocks have special physical links that don't make sense when the DO is not emitted at the end, but they would be shown even if that block was omitted. These issues can be seen here (edited to remove non-essential bits) ``` START B0 (2 cycles) mov(8) g126<1>UD 0x3f800000UD END B0 ->B1 START B2 <-B1 <-B4 (0 cycles) END B2 ->B3 START B3 <-B2 (260 cycles) LABEL1: mov(8) g1<1>D 0D cmp.ge.f0.0(8) null<1>D g2<0,1,0>D 10D sync nop(1) null<0,1,0>UB send(1) g0UD g1UD nullUD (+f0.0) break(8) JIP: LABEL0 UIP: LABEL0 END B3 ->B1 ->B5 ->B4 START B4 <-B3 (1000 cycles) sync nop(1) null<0,1,0>UB mov(8) g126<1>UD g0<0,1,0>UD LABEL0: while(8) JIP: LABEL1 END B4 ->B2 START B5 <-B1 <-B3 (20 cycles) ``` For example: - Block 1 is missing (a skipped DO block) - Block 2 is empty (it was a FLOW block) - Block 3 ends with a link to Block 1 (the special links involving DO blocks). Two key changes were made to fix this. First, skip the DO and FLOW blocks completely. The use_tail ensures that the instruction group is reused to avoid empty blocks. Second, when printing, the successors and predecessors, walk through the skipped blocks. And finally, don't print the special blocks. With the fix, here's the output. Note the blocks retain their original BRW IR number. ``` START B0 (2 cycles) mov(8) g127<1>UD 0x3f800000UD END B0 ->B3 START B3 <-B0 <-B4 (260 cycles) LABEL1: mov(8) g1<1>D 0D cmp.ge.f0.0(8) null<1>D g2<0,1,0>D 10D sync nop(1) null<0,1,0>UB send(1) g0UD g1UD nullUD (+f0.0) break(8) JIP: LABEL0 UIP: LABEL0 END B3 ->B5 ->B4 START B4 <-B3 (1000 cycles) sync nop(1) null<0,1,0>UB mov(8) g127<1>UD g0<0,1,0>UD LABEL0: while(8) JIP: LABEL1 END B4 ->B3 START B5 <-B3 (20 cycles) ``` Issue was spotted by Ken. Fixes: d2c39b17793 ("intel/brw: Always have a (non-DO) block after a DO in the CFG") Reviewed-by: Kenneth Graunke <kenneth@whitecape.org> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/36226>
2025-07-18 09:40:23 -07:00
static bool
is_do_block(struct bblock_t *block)
{
return block->start()->opcode == BRW_OPCODE_DO;
}
static bool
is_flow_block(struct bblock_t *block)
{
return block->start()->opcode == SHADER_OPCODE_FLOW;
}
static bool
should_omit_link(struct bblock_t *block,
struct bblock_link *link)
{
return link->kind == bblock_link_physical &&
(is_do_block(block) || is_do_block(link->block));
}
static void
print_successors_for_disasm(FILE *f, struct bblock_t *block)
brw: Fix printing of blocks in disassembly when BRW is available When disassembling and BRW IR is available (which happens in the generator), there will be pointers to the BRW's basic block structures that are used to print the block numbers and predecessor/successors in the output. There are two challenges: - Because DO and FLOW instructions are not real instructions, they are not emitted in the output but would still cause the output to contain empty blocks. Previous code accounted for DO but still had problems. - DO blocks have special physical links that don't make sense when the DO is not emitted at the end, but they would be shown even if that block was omitted. These issues can be seen here (edited to remove non-essential bits) ``` START B0 (2 cycles) mov(8) g126<1>UD 0x3f800000UD END B0 ->B1 START B2 <-B1 <-B4 (0 cycles) END B2 ->B3 START B3 <-B2 (260 cycles) LABEL1: mov(8) g1<1>D 0D cmp.ge.f0.0(8) null<1>D g2<0,1,0>D 10D sync nop(1) null<0,1,0>UB send(1) g0UD g1UD nullUD (+f0.0) break(8) JIP: LABEL0 UIP: LABEL0 END B3 ->B1 ->B5 ->B4 START B4 <-B3 (1000 cycles) sync nop(1) null<0,1,0>UB mov(8) g126<1>UD g0<0,1,0>UD LABEL0: while(8) JIP: LABEL1 END B4 ->B2 START B5 <-B1 <-B3 (20 cycles) ``` For example: - Block 1 is missing (a skipped DO block) - Block 2 is empty (it was a FLOW block) - Block 3 ends with a link to Block 1 (the special links involving DO blocks). Two key changes were made to fix this. First, skip the DO and FLOW blocks completely. The use_tail ensures that the instruction group is reused to avoid empty blocks. Second, when printing, the successors and predecessors, walk through the skipped blocks. And finally, don't print the special blocks. With the fix, here's the output. Note the blocks retain their original BRW IR number. ``` START B0 (2 cycles) mov(8) g127<1>UD 0x3f800000UD END B0 ->B3 START B3 <-B0 <-B4 (260 cycles) LABEL1: mov(8) g1<1>D 0D cmp.ge.f0.0(8) null<1>D g2<0,1,0>D 10D sync nop(1) null<0,1,0>UB send(1) g0UD g1UD nullUD (+f0.0) break(8) JIP: LABEL0 UIP: LABEL0 END B3 ->B5 ->B4 START B4 <-B3 (1000 cycles) sync nop(1) null<0,1,0>UB mov(8) g127<1>UD g0<0,1,0>UD LABEL0: while(8) JIP: LABEL1 END B4 ->B3 START B5 <-B3 (20 cycles) ``` Issue was spotted by Ken. Fixes: d2c39b17793 ("intel/brw: Always have a (non-DO) block after a DO in the CFG") Reviewed-by: Kenneth Graunke <kenneth@whitecape.org> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/36226>
2025-07-18 09:40:23 -07:00
{
brw_foreach_list_typed(struct bblock_link, succ, link,
&block->children) {
if (should_omit_link(block, succ))
continue;
if (is_do_block(succ->block) || is_flow_block(succ->block))
print_successors_for_disasm(f, succ->block);
brw: Fix printing of blocks in disassembly when BRW is available When disassembling and BRW IR is available (which happens in the generator), there will be pointers to the BRW's basic block structures that are used to print the block numbers and predecessor/successors in the output. There are two challenges: - Because DO and FLOW instructions are not real instructions, they are not emitted in the output but would still cause the output to contain empty blocks. Previous code accounted for DO but still had problems. - DO blocks have special physical links that don't make sense when the DO is not emitted at the end, but they would be shown even if that block was omitted. These issues can be seen here (edited to remove non-essential bits) ``` START B0 (2 cycles) mov(8) g126<1>UD 0x3f800000UD END B0 ->B1 START B2 <-B1 <-B4 (0 cycles) END B2 ->B3 START B3 <-B2 (260 cycles) LABEL1: mov(8) g1<1>D 0D cmp.ge.f0.0(8) null<1>D g2<0,1,0>D 10D sync nop(1) null<0,1,0>UB send(1) g0UD g1UD nullUD (+f0.0) break(8) JIP: LABEL0 UIP: LABEL0 END B3 ->B1 ->B5 ->B4 START B4 <-B3 (1000 cycles) sync nop(1) null<0,1,0>UB mov(8) g126<1>UD g0<0,1,0>UD LABEL0: while(8) JIP: LABEL1 END B4 ->B2 START B5 <-B1 <-B3 (20 cycles) ``` For example: - Block 1 is missing (a skipped DO block) - Block 2 is empty (it was a FLOW block) - Block 3 ends with a link to Block 1 (the special links involving DO blocks). Two key changes were made to fix this. First, skip the DO and FLOW blocks completely. The use_tail ensures that the instruction group is reused to avoid empty blocks. Second, when printing, the successors and predecessors, walk through the skipped blocks. And finally, don't print the special blocks. With the fix, here's the output. Note the blocks retain their original BRW IR number. ``` START B0 (2 cycles) mov(8) g127<1>UD 0x3f800000UD END B0 ->B3 START B3 <-B0 <-B4 (260 cycles) LABEL1: mov(8) g1<1>D 0D cmp.ge.f0.0(8) null<1>D g2<0,1,0>D 10D sync nop(1) null<0,1,0>UB send(1) g0UD g1UD nullUD (+f0.0) break(8) JIP: LABEL0 UIP: LABEL0 END B3 ->B5 ->B4 START B4 <-B3 (1000 cycles) sync nop(1) null<0,1,0>UB mov(8) g127<1>UD g0<0,1,0>UD LABEL0: while(8) JIP: LABEL1 END B4 ->B3 START B5 <-B3 (20 cycles) ``` Issue was spotted by Ken. Fixes: d2c39b17793 ("intel/brw: Always have a (non-DO) block after a DO in the CFG") Reviewed-by: Kenneth Graunke <kenneth@whitecape.org> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/36226>
2025-07-18 09:40:23 -07:00
else
fprintf(f, " ->B%d", succ->block->num);
brw: Fix printing of blocks in disassembly when BRW is available When disassembling and BRW IR is available (which happens in the generator), there will be pointers to the BRW's basic block structures that are used to print the block numbers and predecessor/successors in the output. There are two challenges: - Because DO and FLOW instructions are not real instructions, they are not emitted in the output but would still cause the output to contain empty blocks. Previous code accounted for DO but still had problems. - DO blocks have special physical links that don't make sense when the DO is not emitted at the end, but they would be shown even if that block was omitted. These issues can be seen here (edited to remove non-essential bits) ``` START B0 (2 cycles) mov(8) g126<1>UD 0x3f800000UD END B0 ->B1 START B2 <-B1 <-B4 (0 cycles) END B2 ->B3 START B3 <-B2 (260 cycles) LABEL1: mov(8) g1<1>D 0D cmp.ge.f0.0(8) null<1>D g2<0,1,0>D 10D sync nop(1) null<0,1,0>UB send(1) g0UD g1UD nullUD (+f0.0) break(8) JIP: LABEL0 UIP: LABEL0 END B3 ->B1 ->B5 ->B4 START B4 <-B3 (1000 cycles) sync nop(1) null<0,1,0>UB mov(8) g126<1>UD g0<0,1,0>UD LABEL0: while(8) JIP: LABEL1 END B4 ->B2 START B5 <-B1 <-B3 (20 cycles) ``` For example: - Block 1 is missing (a skipped DO block) - Block 2 is empty (it was a FLOW block) - Block 3 ends with a link to Block 1 (the special links involving DO blocks). Two key changes were made to fix this. First, skip the DO and FLOW blocks completely. The use_tail ensures that the instruction group is reused to avoid empty blocks. Second, when printing, the successors and predecessors, walk through the skipped blocks. And finally, don't print the special blocks. With the fix, here's the output. Note the blocks retain their original BRW IR number. ``` START B0 (2 cycles) mov(8) g127<1>UD 0x3f800000UD END B0 ->B3 START B3 <-B0 <-B4 (260 cycles) LABEL1: mov(8) g1<1>D 0D cmp.ge.f0.0(8) null<1>D g2<0,1,0>D 10D sync nop(1) null<0,1,0>UB send(1) g0UD g1UD nullUD (+f0.0) break(8) JIP: LABEL0 UIP: LABEL0 END B3 ->B5 ->B4 START B4 <-B3 (1000 cycles) sync nop(1) null<0,1,0>UB mov(8) g127<1>UD g0<0,1,0>UD LABEL0: while(8) JIP: LABEL1 END B4 ->B3 START B5 <-B3 (20 cycles) ``` Issue was spotted by Ken. Fixes: d2c39b17793 ("intel/brw: Always have a (non-DO) block after a DO in the CFG") Reviewed-by: Kenneth Graunke <kenneth@whitecape.org> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/36226>
2025-07-18 09:40:23 -07:00
}
}
static void
print_predecessors_for_disasm(FILE *f, struct bblock_t *block)
brw: Fix printing of blocks in disassembly when BRW is available When disassembling and BRW IR is available (which happens in the generator), there will be pointers to the BRW's basic block structures that are used to print the block numbers and predecessor/successors in the output. There are two challenges: - Because DO and FLOW instructions are not real instructions, they are not emitted in the output but would still cause the output to contain empty blocks. Previous code accounted for DO but still had problems. - DO blocks have special physical links that don't make sense when the DO is not emitted at the end, but they would be shown even if that block was omitted. These issues can be seen here (edited to remove non-essential bits) ``` START B0 (2 cycles) mov(8) g126<1>UD 0x3f800000UD END B0 ->B1 START B2 <-B1 <-B4 (0 cycles) END B2 ->B3 START B3 <-B2 (260 cycles) LABEL1: mov(8) g1<1>D 0D cmp.ge.f0.0(8) null<1>D g2<0,1,0>D 10D sync nop(1) null<0,1,0>UB send(1) g0UD g1UD nullUD (+f0.0) break(8) JIP: LABEL0 UIP: LABEL0 END B3 ->B1 ->B5 ->B4 START B4 <-B3 (1000 cycles) sync nop(1) null<0,1,0>UB mov(8) g126<1>UD g0<0,1,0>UD LABEL0: while(8) JIP: LABEL1 END B4 ->B2 START B5 <-B1 <-B3 (20 cycles) ``` For example: - Block 1 is missing (a skipped DO block) - Block 2 is empty (it was a FLOW block) - Block 3 ends with a link to Block 1 (the special links involving DO blocks). Two key changes were made to fix this. First, skip the DO and FLOW blocks completely. The use_tail ensures that the instruction group is reused to avoid empty blocks. Second, when printing, the successors and predecessors, walk through the skipped blocks. And finally, don't print the special blocks. With the fix, here's the output. Note the blocks retain their original BRW IR number. ``` START B0 (2 cycles) mov(8) g127<1>UD 0x3f800000UD END B0 ->B3 START B3 <-B0 <-B4 (260 cycles) LABEL1: mov(8) g1<1>D 0D cmp.ge.f0.0(8) null<1>D g2<0,1,0>D 10D sync nop(1) null<0,1,0>UB send(1) g0UD g1UD nullUD (+f0.0) break(8) JIP: LABEL0 UIP: LABEL0 END B3 ->B5 ->B4 START B4 <-B3 (1000 cycles) sync nop(1) null<0,1,0>UB mov(8) g127<1>UD g0<0,1,0>UD LABEL0: while(8) JIP: LABEL1 END B4 ->B3 START B5 <-B3 (20 cycles) ``` Issue was spotted by Ken. Fixes: d2c39b17793 ("intel/brw: Always have a (non-DO) block after a DO in the CFG") Reviewed-by: Kenneth Graunke <kenneth@whitecape.org> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/36226>
2025-07-18 09:40:23 -07:00
{
brw_foreach_list_typed(struct bblock_link, pred, link,
&block->parents) {
if (should_omit_link(block, pred))
continue;
if (is_do_block(pred->block) || is_flow_block(pred->block))
print_predecessors_for_disasm(f, pred->block);
brw: Fix printing of blocks in disassembly when BRW is available When disassembling and BRW IR is available (which happens in the generator), there will be pointers to the BRW's basic block structures that are used to print the block numbers and predecessor/successors in the output. There are two challenges: - Because DO and FLOW instructions are not real instructions, they are not emitted in the output but would still cause the output to contain empty blocks. Previous code accounted for DO but still had problems. - DO blocks have special physical links that don't make sense when the DO is not emitted at the end, but they would be shown even if that block was omitted. These issues can be seen here (edited to remove non-essential bits) ``` START B0 (2 cycles) mov(8) g126<1>UD 0x3f800000UD END B0 ->B1 START B2 <-B1 <-B4 (0 cycles) END B2 ->B3 START B3 <-B2 (260 cycles) LABEL1: mov(8) g1<1>D 0D cmp.ge.f0.0(8) null<1>D g2<0,1,0>D 10D sync nop(1) null<0,1,0>UB send(1) g0UD g1UD nullUD (+f0.0) break(8) JIP: LABEL0 UIP: LABEL0 END B3 ->B1 ->B5 ->B4 START B4 <-B3 (1000 cycles) sync nop(1) null<0,1,0>UB mov(8) g126<1>UD g0<0,1,0>UD LABEL0: while(8) JIP: LABEL1 END B4 ->B2 START B5 <-B1 <-B3 (20 cycles) ``` For example: - Block 1 is missing (a skipped DO block) - Block 2 is empty (it was a FLOW block) - Block 3 ends with a link to Block 1 (the special links involving DO blocks). Two key changes were made to fix this. First, skip the DO and FLOW blocks completely. The use_tail ensures that the instruction group is reused to avoid empty blocks. Second, when printing, the successors and predecessors, walk through the skipped blocks. And finally, don't print the special blocks. With the fix, here's the output. Note the blocks retain their original BRW IR number. ``` START B0 (2 cycles) mov(8) g127<1>UD 0x3f800000UD END B0 ->B3 START B3 <-B0 <-B4 (260 cycles) LABEL1: mov(8) g1<1>D 0D cmp.ge.f0.0(8) null<1>D g2<0,1,0>D 10D sync nop(1) null<0,1,0>UB send(1) g0UD g1UD nullUD (+f0.0) break(8) JIP: LABEL0 UIP: LABEL0 END B3 ->B5 ->B4 START B4 <-B3 (1000 cycles) sync nop(1) null<0,1,0>UB mov(8) g127<1>UD g0<0,1,0>UD LABEL0: while(8) JIP: LABEL1 END B4 ->B3 START B5 <-B3 (20 cycles) ``` Issue was spotted by Ken. Fixes: d2c39b17793 ("intel/brw: Always have a (non-DO) block after a DO in the CFG") Reviewed-by: Kenneth Graunke <kenneth@whitecape.org> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/36226>
2025-07-18 09:40:23 -07:00
else
fprintf(f, " <-B%d", pred->block->num);
brw: Fix printing of blocks in disassembly when BRW is available When disassembling and BRW IR is available (which happens in the generator), there will be pointers to the BRW's basic block structures that are used to print the block numbers and predecessor/successors in the output. There are two challenges: - Because DO and FLOW instructions are not real instructions, they are not emitted in the output but would still cause the output to contain empty blocks. Previous code accounted for DO but still had problems. - DO blocks have special physical links that don't make sense when the DO is not emitted at the end, but they would be shown even if that block was omitted. These issues can be seen here (edited to remove non-essential bits) ``` START B0 (2 cycles) mov(8) g126<1>UD 0x3f800000UD END B0 ->B1 START B2 <-B1 <-B4 (0 cycles) END B2 ->B3 START B3 <-B2 (260 cycles) LABEL1: mov(8) g1<1>D 0D cmp.ge.f0.0(8) null<1>D g2<0,1,0>D 10D sync nop(1) null<0,1,0>UB send(1) g0UD g1UD nullUD (+f0.0) break(8) JIP: LABEL0 UIP: LABEL0 END B3 ->B1 ->B5 ->B4 START B4 <-B3 (1000 cycles) sync nop(1) null<0,1,0>UB mov(8) g126<1>UD g0<0,1,0>UD LABEL0: while(8) JIP: LABEL1 END B4 ->B2 START B5 <-B1 <-B3 (20 cycles) ``` For example: - Block 1 is missing (a skipped DO block) - Block 2 is empty (it was a FLOW block) - Block 3 ends with a link to Block 1 (the special links involving DO blocks). Two key changes were made to fix this. First, skip the DO and FLOW blocks completely. The use_tail ensures that the instruction group is reused to avoid empty blocks. Second, when printing, the successors and predecessors, walk through the skipped blocks. And finally, don't print the special blocks. With the fix, here's the output. Note the blocks retain their original BRW IR number. ``` START B0 (2 cycles) mov(8) g127<1>UD 0x3f800000UD END B0 ->B3 START B3 <-B0 <-B4 (260 cycles) LABEL1: mov(8) g1<1>D 0D cmp.ge.f0.0(8) null<1>D g2<0,1,0>D 10D sync nop(1) null<0,1,0>UB send(1) g0UD g1UD nullUD (+f0.0) break(8) JIP: LABEL0 UIP: LABEL0 END B3 ->B5 ->B4 START B4 <-B3 (1000 cycles) sync nop(1) null<0,1,0>UB mov(8) g127<1>UD g0<0,1,0>UD LABEL0: while(8) JIP: LABEL1 END B4 ->B3 START B5 <-B3 (20 cycles) ``` Issue was spotted by Ken. Fixes: d2c39b17793 ("intel/brw: Always have a (non-DO) block after a DO in the CFG") Reviewed-by: Kenneth Graunke <kenneth@whitecape.org> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/36226>
2025-07-18 09:40:23 -07:00
}
}
void
dump_assembly(void *assembly, int start_offset, int end_offset,
struct disasm_info *disasm, const unsigned *block_latency, FILE *f)
{
const struct brw_isa_info *isa = disasm->isa;
const char *last_annotation_string = NULL;
void *mem_ctx = ralloc_context(NULL);
const struct brw_label *root_label =
brw_label_assembly(isa, assembly, start_offset, end_offset, mem_ctx);
brw_foreach_list_typed(struct inst_group, group, link, &disasm->group_list) {
struct brw_exec_node *next_node = brw_exec_node_get_next(&group->link);
if (brw_exec_node_is_tail_sentinel(next_node))
break;
struct inst_group *next =
brw_exec_node_data(struct inst_group, next_node, link);
int start_offset = group->offset;
int end_offset = next->offset;
if (group->block_start) {
fprintf(f, " START B%d", group->block_start->num);
print_predecessors_for_disasm(f, group->block_start);
if (block_latency)
fprintf(f, " (%u cycles)",
block_latency[group->block_start->num]);
fprintf(f, "\n");
}
if (last_annotation_string != group->annotation) {
last_annotation_string = group->annotation;
if (last_annotation_string)
fprintf(f, " %s\n", last_annotation_string);
}
brw_disassemble(isa, assembly, start_offset, end_offset,
root_label, NULL, f);
if (group->error) {
fputs(group->error, f);
}
if (group->block_end) {
fprintf(f, " END B%d", group->block_end->num);
print_successors_for_disasm(f, group->block_end);
fprintf(f, "\n");
}
}
fprintf(f, "\n");
ralloc_free(mem_ctx);
}
struct disasm_info *
disasm_initialize(const struct brw_isa_info *isa,
const struct cfg_t *cfg)
{
struct disasm_info *disasm = ralloc(NULL, struct disasm_info);
brw_exec_list_make_empty(&disasm->group_list);
disasm->isa = isa;
disasm->cfg = cfg;
disasm->cur_block = 0;
disasm->use_tail = false;
return disasm;
}
struct inst_group *
disasm_new_inst_group(struct disasm_info *disasm, int next_inst_offset)
{
assert(next_inst_offset >= 0);
struct inst_group *tail = rzalloc(disasm, struct inst_group);
tail->offset = next_inst_offset;
brw_exec_list_push_tail(&disasm->group_list, &tail->link);
return tail;
}
void
disasm_annotate(struct disasm_info *disasm,
brw_inst *inst, int offset)
{
const struct cfg_t *cfg = disasm->cfg;
struct inst_group *group;
if (!disasm->use_tail) {
group = disasm_new_inst_group(disasm, offset);
} else {
disasm->use_tail = false;
group = brw_exec_node_data(struct inst_group,
brw_exec_list_get_tail_raw(&disasm->group_list), link);
}
#ifndef NDEBUG
if (INTEL_DEBUG(DEBUG_ANNOTATION)) {
group->annotation = inst->annotation;
}
#endif
brw: Fix printing of blocks in disassembly when BRW is available When disassembling and BRW IR is available (which happens in the generator), there will be pointers to the BRW's basic block structures that are used to print the block numbers and predecessor/successors in the output. There are two challenges: - Because DO and FLOW instructions are not real instructions, they are not emitted in the output but would still cause the output to contain empty blocks. Previous code accounted for DO but still had problems. - DO blocks have special physical links that don't make sense when the DO is not emitted at the end, but they would be shown even if that block was omitted. These issues can be seen here (edited to remove non-essential bits) ``` START B0 (2 cycles) mov(8) g126<1>UD 0x3f800000UD END B0 ->B1 START B2 <-B1 <-B4 (0 cycles) END B2 ->B3 START B3 <-B2 (260 cycles) LABEL1: mov(8) g1<1>D 0D cmp.ge.f0.0(8) null<1>D g2<0,1,0>D 10D sync nop(1) null<0,1,0>UB send(1) g0UD g1UD nullUD (+f0.0) break(8) JIP: LABEL0 UIP: LABEL0 END B3 ->B1 ->B5 ->B4 START B4 <-B3 (1000 cycles) sync nop(1) null<0,1,0>UB mov(8) g126<1>UD g0<0,1,0>UD LABEL0: while(8) JIP: LABEL1 END B4 ->B2 START B5 <-B1 <-B3 (20 cycles) ``` For example: - Block 1 is missing (a skipped DO block) - Block 2 is empty (it was a FLOW block) - Block 3 ends with a link to Block 1 (the special links involving DO blocks). Two key changes were made to fix this. First, skip the DO and FLOW blocks completely. The use_tail ensures that the instruction group is reused to avoid empty blocks. Second, when printing, the successors and predecessors, walk through the skipped blocks. And finally, don't print the special blocks. With the fix, here's the output. Note the blocks retain their original BRW IR number. ``` START B0 (2 cycles) mov(8) g127<1>UD 0x3f800000UD END B0 ->B3 START B3 <-B0 <-B4 (260 cycles) LABEL1: mov(8) g1<1>D 0D cmp.ge.f0.0(8) null<1>D g2<0,1,0>D 10D sync nop(1) null<0,1,0>UB send(1) g0UD g1UD nullUD (+f0.0) break(8) JIP: LABEL0 UIP: LABEL0 END B3 ->B5 ->B4 START B4 <-B3 (1000 cycles) sync nop(1) null<0,1,0>UB mov(8) g127<1>UD g0<0,1,0>UD LABEL0: while(8) JIP: LABEL1 END B4 ->B3 START B5 <-B3 (20 cycles) ``` Issue was spotted by Ken. Fixes: d2c39b17793 ("intel/brw: Always have a (non-DO) block after a DO in the CFG") Reviewed-by: Kenneth Graunke <kenneth@whitecape.org> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/36226>
2025-07-18 09:40:23 -07:00
if (inst->opcode == BRW_OPCODE_DO ||
inst->opcode == SHADER_OPCODE_FLOW) {
disasm->use_tail = true;
disasm->cur_block++;
return;
}
brw: Fix printing of blocks in disassembly when BRW is available When disassembling and BRW IR is available (which happens in the generator), there will be pointers to the BRW's basic block structures that are used to print the block numbers and predecessor/successors in the output. There are two challenges: - Because DO and FLOW instructions are not real instructions, they are not emitted in the output but would still cause the output to contain empty blocks. Previous code accounted for DO but still had problems. - DO blocks have special physical links that don't make sense when the DO is not emitted at the end, but they would be shown even if that block was omitted. These issues can be seen here (edited to remove non-essential bits) ``` START B0 (2 cycles) mov(8) g126<1>UD 0x3f800000UD END B0 ->B1 START B2 <-B1 <-B4 (0 cycles) END B2 ->B3 START B3 <-B2 (260 cycles) LABEL1: mov(8) g1<1>D 0D cmp.ge.f0.0(8) null<1>D g2<0,1,0>D 10D sync nop(1) null<0,1,0>UB send(1) g0UD g1UD nullUD (+f0.0) break(8) JIP: LABEL0 UIP: LABEL0 END B3 ->B1 ->B5 ->B4 START B4 <-B3 (1000 cycles) sync nop(1) null<0,1,0>UB mov(8) g126<1>UD g0<0,1,0>UD LABEL0: while(8) JIP: LABEL1 END B4 ->B2 START B5 <-B1 <-B3 (20 cycles) ``` For example: - Block 1 is missing (a skipped DO block) - Block 2 is empty (it was a FLOW block) - Block 3 ends with a link to Block 1 (the special links involving DO blocks). Two key changes were made to fix this. First, skip the DO and FLOW blocks completely. The use_tail ensures that the instruction group is reused to avoid empty blocks. Second, when printing, the successors and predecessors, walk through the skipped blocks. And finally, don't print the special blocks. With the fix, here's the output. Note the blocks retain their original BRW IR number. ``` START B0 (2 cycles) mov(8) g127<1>UD 0x3f800000UD END B0 ->B3 START B3 <-B0 <-B4 (260 cycles) LABEL1: mov(8) g1<1>D 0D cmp.ge.f0.0(8) null<1>D g2<0,1,0>D 10D sync nop(1) null<0,1,0>UB send(1) g0UD g1UD nullUD (+f0.0) break(8) JIP: LABEL0 UIP: LABEL0 END B3 ->B5 ->B4 START B4 <-B3 (1000 cycles) sync nop(1) null<0,1,0>UB mov(8) g127<1>UD g0<0,1,0>UD LABEL0: while(8) JIP: LABEL1 END B4 ->B3 START B5 <-B3 (20 cycles) ``` Issue was spotted by Ken. Fixes: d2c39b17793 ("intel/brw: Always have a (non-DO) block after a DO in the CFG") Reviewed-by: Kenneth Graunke <kenneth@whitecape.org> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/36226>
2025-07-18 09:40:23 -07:00
if (cfg->blocks[disasm->cur_block]->start() == inst) {
group->block_start = cfg->blocks[disasm->cur_block];
}
if (cfg->blocks[disasm->cur_block]->end() == inst) {
group->block_end = cfg->blocks[disasm->cur_block];
disasm->cur_block++;
}
}
void
disasm_insert_error(struct disasm_info *disasm, int offset,
int inst_size, const char *error)
{
brw_foreach_list_typed(struct inst_group, cur, link, &disasm->group_list) {
struct brw_exec_node *next_node = brw_exec_node_get_next(&cur->link);
if (brw_exec_node_is_tail_sentinel(next_node))
break;
struct inst_group *next =
brw_exec_node_data(struct inst_group, next_node, link);
if (next->offset <= offset)
continue;
intel/eu: Handle compaction when inserting validation errors When the EU validator encountered an error, it would add an annotation to the disassembly. Unfortunately, the code to insert an error assumed that the next instruction would start at (offset + sizeof(brw_inst)), which is not true if the instruction with an error is compacted. This could lead to cascading disassembly errors, where we started trying to decode the next instruction at the wrong offset, and getting lots of scary looking output: ERROR: Register Regioning patterns where [...] (-f0.1.any16h) illegal(*** invalid execution size value 6 ) { align1 $7.src atomic }; (+f0.1.any16h) illegal.sat(*** invalid execution size value 6 ) { align1 $9.src AccWrEnable }; illegal(*** invalid execution size value 6 ) { align1 $11.src }; (+f0.1) illegal.sat(*** invalid execution size value 6 ) { align1 F@2 AccWrEnable }; (+f0.1) illegal.sat(*** invalid execution size value 6 ) { align1 F@2 AccWrEnable }; (+f0.1) illegal.sat(*** invalid execution size value 6 ) { align1 $15.src AccWrEnable }; illegal(*** invalid execution size value 6 ) { align1 $15.src }; (+f0.1) illegal.sat.g.f0.1(*** invalid execution size value 6 ) { align1 $13.src AccWrEnable }; Only the first instruction was actually wrong - the rest are just a result of starting the disassembler at the wrong offset. Trash ensues! To fix this, just pass the instruction size in a few layers so we can record the next offset properly. Cc: mesa-stable Reviewed-by: Francisco Jerez <currojerez@riseup.net> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/17624>
2022-07-19 00:27:29 -07:00
if (offset + inst_size != next->offset) {
struct inst_group *new_group = ralloc(disasm, struct inst_group);
memcpy(new_group, cur, sizeof(struct inst_group));
cur->error = NULL;
cur->error_length = 0;
cur->block_end = NULL;
new_group->offset = offset + inst_size;
new_group->block_start = NULL;
brw_exec_node_insert_after(&cur->link, &new_group->link);
}
if (cur->error)
ralloc_strcat(&cur->error, error);
else
cur->error = ralloc_strdup(disasm, error);
return;
}
}