Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/amd/compiler/aco_print_asm.cpp
4550 views
1
/*
2
* Copyright © 2018 Valve 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
25
#include "aco_ir.h"
26
27
#include "llvm/ac_llvm_util.h"
28
29
#include "llvm-c/Disassembler.h"
30
#include <llvm/ADT/StringRef.h>
31
#include <llvm/MC/MCDisassembler/MCDisassembler.h>
32
33
#include <array>
34
#include <iomanip>
35
#include <vector>
36
37
namespace aco {
38
namespace {
39
40
/* LLVM disassembler only supports GFX8+, try to disassemble with CLRXdisasm
41
* for GFX6-GFX7 if found on the system, this is better than nothing.
42
*/
43
bool
44
print_asm_gfx6_gfx7(Program* program, std::vector<uint32_t>& binary, FILE* output)
45
{
46
#ifdef _WIN32
47
return true;
48
#else
49
char path[] = "/tmp/fileXXXXXX";
50
char line[2048], command[128];
51
const char* gpu_type;
52
FILE* p;
53
int fd;
54
55
/* Dump the binary into a temporary file. */
56
fd = mkstemp(path);
57
if (fd < 0)
58
return true;
59
60
for (uint32_t w : binary) {
61
if (write(fd, &w, sizeof(w)) == -1)
62
goto fail;
63
}
64
65
/* Determine the GPU type for CLRXdisasm. Use the family for GFX6 chips
66
* because it doesn't allow to use gfx600 directly.
67
*/
68
switch (program->chip_class) {
69
case GFX6:
70
switch (program->family) {
71
case CHIP_TAHITI: gpu_type = "tahiti"; break;
72
case CHIP_PITCAIRN: gpu_type = "pitcairn"; break;
73
case CHIP_VERDE: gpu_type = "capeverde"; break;
74
case CHIP_OLAND: gpu_type = "oland"; break;
75
case CHIP_HAINAN: gpu_type = "hainan"; break;
76
default: unreachable("Invalid GFX6 family!");
77
}
78
break;
79
case GFX7: gpu_type = "gfx700"; break;
80
default: unreachable("Invalid chip class!");
81
}
82
83
sprintf(command, "clrxdisasm --gpuType=%s -r %s", gpu_type, path);
84
85
p = popen(command, "r");
86
if (p) {
87
if (!fgets(line, sizeof(line), p)) {
88
fprintf(output, "clrxdisasm not found\n");
89
pclose(p);
90
goto fail;
91
}
92
93
do {
94
fputs(line, output);
95
} while (fgets(line, sizeof(line), p));
96
97
pclose(p);
98
}
99
100
return false;
101
102
fail:
103
close(fd);
104
unlink(path);
105
return true;
106
#endif
107
}
108
109
std::pair<bool, size_t>
110
disasm_instr(chip_class chip, LLVMDisasmContextRef disasm, uint32_t* binary, unsigned exec_size,
111
size_t pos, char* outline, unsigned outline_size)
112
{
113
/* mask out src2 on v_writelane_b32 */
114
if (((chip == GFX8 || chip == GFX9) && (binary[pos] & 0xffff8000) == 0xd28a0000) ||
115
(chip >= GFX10 && (binary[pos] & 0xffff8000) == 0xd7610000)) {
116
binary[pos + 1] = binary[pos + 1] & 0xF803FFFF;
117
}
118
119
size_t l =
120
LLVMDisasmInstruction(disasm, (uint8_t*)&binary[pos], (exec_size - pos) * sizeof(uint32_t),
121
pos * 4, outline, outline_size);
122
123
if (chip >= GFX10 && l == 8 && ((binary[pos] & 0xffff0000) == 0xd7610000) &&
124
((binary[pos + 1] & 0x1ff) == 0xff)) {
125
/* v_writelane with literal uses 3 dwords but llvm consumes only 2 */
126
l += 4;
127
}
128
129
bool invalid = false;
130
size_t size;
131
if (!l &&
132
((chip >= GFX9 && (binary[pos] & 0xffff8000) == 0xd1348000) || /* v_add_u32_e64 + clamp */
133
(chip >= GFX10 && (binary[pos] & 0xffff8000) == 0xd7038000) || /* v_add_u16_e64 + clamp */
134
(chip <= GFX9 && (binary[pos] & 0xffff8000) == 0xd1268000) || /* v_add_u16_e64 + clamp */
135
(chip >= GFX10 && (binary[pos] & 0xffff8000) == 0xd76d8000) || /* v_add3_u32 + clamp */
136
(chip == GFX9 && (binary[pos] & 0xffff8000) == 0xd1ff8000)) /* v_add3_u32 + clamp */) {
137
strcpy(outline, "\tinteger addition + clamp");
138
bool has_literal = chip >= GFX10 && (((binary[pos + 1] & 0x1ff) == 0xff) ||
139
(((binary[pos + 1] >> 9) & 0x1ff) == 0xff));
140
size = 2 + has_literal;
141
} else if (chip >= GFX10 && l == 4 && ((binary[pos] & 0xfe0001ff) == 0x020000f9)) {
142
strcpy(outline, "\tv_cndmask_b32 + sdwa");
143
size = 2;
144
} else if (!l) {
145
strcpy(outline, "(invalid instruction)");
146
size = 1;
147
invalid = true;
148
} else {
149
assert(l % 4 == 0);
150
size = l / 4;
151
}
152
153
return std::make_pair(invalid, size);
154
}
155
} /* end namespace */
156
157
bool
158
print_asm(Program* program, std::vector<uint32_t>& binary, unsigned exec_size, FILE* output)
159
{
160
if (program->chip_class <= GFX7) {
161
/* Do not abort if clrxdisasm isn't found. */
162
print_asm_gfx6_gfx7(program, binary, output);
163
return false;
164
}
165
166
std::vector<bool> referenced_blocks(program->blocks.size());
167
referenced_blocks[0] = true;
168
for (Block& block : program->blocks) {
169
for (unsigned succ : block.linear_succs)
170
referenced_blocks[succ] = true;
171
}
172
173
std::vector<llvm::SymbolInfoTy> symbols;
174
std::vector<std::array<char, 16>> block_names;
175
block_names.reserve(program->blocks.size());
176
for (Block& block : program->blocks) {
177
if (!referenced_blocks[block.index])
178
continue;
179
std::array<char, 16> name;
180
sprintf(name.data(), "BB%u", block.index);
181
block_names.push_back(name);
182
symbols.emplace_back(block.offset * 4,
183
llvm::StringRef(block_names[block_names.size() - 1].data()), 0);
184
}
185
186
const char* features = "";
187
if (program->chip_class >= GFX10 && program->wave_size == 64) {
188
features = "+wavefrontsize64";
189
}
190
191
LLVMDisasmContextRef disasm =
192
LLVMCreateDisasmCPUFeatures("amdgcn-mesa-mesa3d", ac_get_llvm_processor_name(program->family),
193
features, &symbols, 0, NULL, NULL);
194
195
size_t pos = 0;
196
bool invalid = false;
197
unsigned next_block = 0;
198
199
unsigned prev_size = 0;
200
unsigned prev_pos = 0;
201
unsigned repeat_count = 0;
202
while (pos < exec_size) {
203
bool new_block =
204
next_block < program->blocks.size() && pos == program->blocks[next_block].offset;
205
if (pos + prev_size <= exec_size && prev_pos != pos && !new_block &&
206
memcmp(&binary[prev_pos], &binary[pos], prev_size * 4) == 0) {
207
repeat_count++;
208
pos += prev_size;
209
continue;
210
} else {
211
if (repeat_count)
212
fprintf(output, "\t(then repeated %u times)\n", repeat_count);
213
repeat_count = 0;
214
}
215
216
while (next_block < program->blocks.size() && pos == program->blocks[next_block].offset) {
217
if (referenced_blocks[next_block])
218
fprintf(output, "BB%u:\n", next_block);
219
next_block++;
220
}
221
222
char outline[1024];
223
std::pair<bool, size_t> res = disasm_instr(program->chip_class, disasm, binary.data(),
224
exec_size, pos, outline, sizeof(outline));
225
invalid |= res.first;
226
227
fprintf(output, "%-60s ;", outline);
228
229
for (unsigned i = 0; i < res.second; i++)
230
fprintf(output, " %.8x", binary[pos + i]);
231
fputc('\n', output);
232
233
prev_size = res.second;
234
prev_pos = pos;
235
pos += res.second;
236
}
237
assert(next_block == program->blocks.size());
238
239
LLVMDisasmDispose(disasm);
240
241
if (program->constant_data.size()) {
242
fputs("\n/* constant data */\n", output);
243
for (unsigned i = 0; i < program->constant_data.size(); i += 32) {
244
fprintf(output, "[%.6u]", i);
245
unsigned line_size = std::min<size_t>(program->constant_data.size() - i, 32);
246
for (unsigned j = 0; j < line_size; j += 4) {
247
unsigned size = std::min<size_t>(program->constant_data.size() - (i + j), 4);
248
uint32_t v = 0;
249
memcpy(&v, &program->constant_data[i + j], size);
250
fprintf(output, " %.8x", v);
251
}
252
fputc('\n', output);
253
}
254
}
255
256
return invalid;
257
}
258
259
} // namespace aco
260
261