4 #include "llvm-c/Disassembler.h"
5 #include "ac_llvm_util.h"
7 #include <llvm/ADT/StringRef.h>
8 #if LLVM_VERSION_MAJOR >= 11
9 #include <llvm/MC/MCDisassembler/MCDisassembler.h>
14 /* LLVM disassembler only supports GFX8+, try to disassemble with CLRXdisasm
15 * for GFX6-GFX7 if found on the system, this is better than nothing.
17 void print_asm_gfx6_gfx7(Program
*program
, std::vector
<uint32_t>& binary
,
20 char path
[] = "/tmp/fileXXXXXX";
21 char line
[2048], command
[128];
26 /* Dump the binary into a temporary file. */
31 for (uint32_t w
: binary
)
33 if (write(fd
, &w
, sizeof(w
)) == -1)
37 /* Determine the GPU type for CLRXdisasm. Use the family for GFX6 chips
38 * because it doesn't allow to use gfx600 directly.
40 switch (program
->chip_class
) {
42 switch (program
->family
) {
47 gpu_type
= "pitcairn";
50 gpu_type
= "capeverde";
59 unreachable("Invalid GFX6 family!");
66 unreachable("Invalid chip class!");
69 sprintf(command
, "clrxdisasm --gpuType=%s -r %s", gpu_type
, path
);
71 p
= popen(command
, "r");
73 if (!fgets(line
, sizeof(line
), p
)) {
74 out
<< "clrxdisasm not found\n";
81 } while (fgets(line
, sizeof(line
), p
));
91 void print_asm(Program
*program
, std::vector
<uint32_t>& binary
,
92 unsigned exec_size
, std::ostream
& out
)
94 if (program
->chip_class
<= GFX7
) {
95 print_asm_gfx6_gfx7(program
, binary
, out
);
99 std::vector
<bool> referenced_blocks(program
->blocks
.size());
100 referenced_blocks
[0] = true;
101 for (Block
& block
: program
->blocks
) {
102 for (unsigned succ
: block
.linear_succs
)
103 referenced_blocks
[succ
] = true;
106 #if LLVM_VERSION_MAJOR >= 11
107 std::vector
<llvm::SymbolInfoTy
> symbols
;
109 std::vector
<std::tuple
<uint64_t, llvm::StringRef
, uint8_t>> symbols
;
111 std::vector
<std::array
<char,16>> block_names
;
112 block_names
.reserve(program
->blocks
.size());
113 for (Block
& block
: program
->blocks
) {
114 if (!referenced_blocks
[block
.index
])
116 std::array
<char, 16> name
;
117 sprintf(name
.data(), "BB%u", block
.index
);
118 block_names
.push_back(name
);
119 symbols
.emplace_back(block
.offset
* 4, llvm::StringRef(block_names
[block_names
.size() - 1].data()), 0);
122 const char *features
= "";
123 if (program
->chip_class
>= GFX10
&& program
->wave_size
== 64) {
124 features
= "+wavefrontsize64";
127 LLVMDisasmContextRef disasm
= LLVMCreateDisasmCPUFeatures("amdgcn-mesa-mesa3d",
128 ac_get_llvm_processor_name(program
->family
),
130 &symbols
, 0, NULL
, NULL
);
134 bool invalid
= false;
135 unsigned next_block
= 0;
136 while (pos
< exec_size
) {
137 while (next_block
< program
->blocks
.size() && pos
== program
->blocks
[next_block
].offset
) {
138 if (referenced_blocks
[next_block
])
139 out
<< "BB" << std::dec
<< next_block
<< ":" << std::endl
;
143 /* mask out src2 on v_writelane_b32 */
144 if (((program
->chip_class
== GFX8
|| program
->chip_class
== GFX9
) && (binary
[pos
] & 0xffff8000) == 0xd28a0000) ||
145 (program
->chip_class
>= GFX10
&& (binary
[pos
] & 0xffff8000) == 0xd7610000)) {
146 binary
[pos
+1] = binary
[pos
+1] & 0xF803FFFF;
149 size_t l
= LLVMDisasmInstruction(disasm
, (uint8_t *) &binary
[pos
],
150 (exec_size
- pos
) * sizeof(uint32_t), pos
* 4,
151 outline
, sizeof(outline
));
154 const int align_width
= 60;
156 ((program
->chip_class
>= GFX9
&& (binary
[pos
] & 0xffff8000) == 0xd1348000) || /* v_add_u32_e64 + clamp */
157 (program
->chip_class
>= GFX10
&& (binary
[pos
] & 0xffff8000) == 0xd7038000) || /* v_add_u16_e64 + clamp */
158 (program
->chip_class
<= GFX9
&& (binary
[pos
] & 0xffff8000) == 0xd1268000)) /* v_add_u16_e64 + clamp */) {
159 out
<< std::left
<< std::setw(align_width
) << std::setfill(' ') << "\tinteger addition + clamp";
160 bool has_literal
= program
->chip_class
>= GFX10
&&
161 (((binary
[pos
+1] & 0x1ff) == 0xff) || (((binary
[pos
+1] >> 9) & 0x1ff) == 0xff));
162 new_pos
= pos
+ 2 + has_literal
;
163 } else if (program
->chip_class
>= GFX10
&& l
== 4 && ((binary
[pos
] & 0xfe0001ff) == 0x020000f9)) {
164 out
<< std::left
<< std::setw(align_width
) << std::setfill(' ') << "\tv_cndmask_b32 + sdwa";
167 out
<< std::left
<< std::setw(align_width
) << std::setfill(' ') << "(invalid instruction)";
171 out
<< std::left
<< std::setw(align_width
) << std::setfill(' ') << outline
;
173 new_pos
= pos
+ l
/ 4;
178 for (; pos
< new_pos
; pos
++)
179 out
<< " " << std::setfill('0') << std::setw(8) << std::hex
<< binary
[pos
];
182 out
<< std::setfill(' ') << std::setw(0) << std::dec
;
183 assert(next_block
== program
->blocks
.size());
185 LLVMDisasmDispose(disasm
);
187 if (program
->constant_data
.size()) {
188 out
<< std::endl
<< "/* constant data */" << std::endl
;
189 for (unsigned i
= 0; i
< program
->constant_data
.size(); i
+= 32) {
190 out
<< '[' << std::setw(6) << std::setfill('0') << std::dec
<< i
<< ']';
191 unsigned line_size
= std::min
<size_t>(program
->constant_data
.size() - i
, 32);
192 for (unsigned j
= 0; j
< line_size
; j
+= 4) {
193 unsigned size
= std::min
<size_t>(program
->constant_data
.size() - (i
+ j
), 4);
195 memcpy(&v
, &program
->constant_data
[i
+ j
], size
);
196 out
<< " " << std::setw(8) << std::setfill('0') << std::hex
<< v
;
202 out
<< std::setfill(' ') << std::setw(0) << std::dec
;
205 /* Invalid instructions usually lead to GPU hangs, which can make
206 * getting the actual invalid instruction hard. Abort here so that we
207 * can find the problem.