radeonsi: use the new run-time linker for shaders

v2:
- fix a memory leak

Reviewed-by: Marek Olšák <marek.olsak@amd.com>
This commit is contained in:
Nicolai Hähnle
2018-05-22 16:14:16 +02:00
committed by Marek Olšák
parent 16bee0e5f6
commit bf8a1ca902
9 changed files with 268 additions and 233 deletions

View File

@@ -32,6 +32,7 @@
#include "util/u_memory.h"
#include "util/u_string.h"
#include "ac_debug.h"
#include "ac_rtld.h"
static void si_dump_bo_list(struct si_context *sctx,
const struct radeon_saved_cs *saved, FILE *f);
@@ -201,15 +202,16 @@ static void si_dump_compute_shader(struct si_context *ctx,
/**
* Shader compiles can be overridden with arbitrary ELF objects by setting
* the environment variable RADEON_REPLACE_SHADERS=num1:filename1[;num2:filename2]
*
* TODO: key this off some hash
*/
bool si_replace_shader(unsigned num, struct ac_shader_binary *binary)
bool si_replace_shader(unsigned num, struct si_shader_binary *binary)
{
const char *p = debug_get_option_replace_shaders();
const char *semicolon;
char *copy = NULL;
FILE *f;
long filesize, nread;
char *buf = NULL;
bool replaced = false;
if (!p)
@@ -265,23 +267,25 @@ bool si_replace_shader(unsigned num, struct ac_shader_binary *binary)
if (fseek(f, 0, SEEK_SET) != 0)
goto file_error;
buf = MALLOC(filesize);
if (!buf) {
binary->elf_buffer = MALLOC(filesize);
if (!binary->elf_buffer) {
fprintf(stderr, "out of memory\n");
goto out_close;
}
nread = fread(buf, 1, filesize, f);
if (nread != filesize)
nread = fread((void*)binary->elf_buffer, 1, filesize, f);
if (nread != filesize) {
FREE((void*)binary->elf_buffer);
binary->elf_buffer = NULL;
goto file_error;
}
ac_elf_read(buf, filesize, binary);
binary->elf_size = nread;
replaced = true;
out_close:
fclose(f);
out_free:
FREE(buf);
free(copy);
return replaced;
@@ -922,33 +926,52 @@ struct si_shader_inst {
};
/**
* Split a disassembly string into instructions and add them to the array
* pointed to by \p instructions.
* Open the given \p binary as \p rtld_binary and split the contained
* disassembly string into instructions and add them to the array
* pointed to by \p instructions, which must be sufficiently large.
*
* Labels are considered to be part of the following instruction.
*
* The caller must keep \p rtld_binary alive as long as \p instructions are
* used and then close it afterwards.
*/
static void si_add_split_disasm(const char *disasm,
static void si_add_split_disasm(struct ac_rtld_binary *rtld_binary,
struct si_shader_binary *binary,
uint64_t *addr,
unsigned *num,
struct si_shader_inst *instructions)
{
const char *semicolon;
if (!ac_rtld_open(rtld_binary, 1, &binary->elf_buffer, &binary->elf_size))
return;
const char *disasm;
size_t nbytes;
if (!ac_rtld_get_section_by_name(rtld_binary, ".AMDGPU.disasm",
&disasm, &nbytes))
return;
const char *end = disasm + nbytes;
while (disasm < end) {
const char *semicolon = memchr(disasm, ';', end - disasm);
if (!semicolon)
break;
while ((semicolon = strchr(disasm, ';'))) {
struct si_shader_inst *inst = &instructions[(*num)++];
const char *end = util_strchrnul(semicolon, '\n');
const char *inst_end = memchr(semicolon + 1, '\n', end - semicolon - 1);
if (!inst_end)
inst_end = end;
inst->text = disasm;
inst->textlen = end - disasm;
inst->textlen = inst_end - disasm;
inst->addr = *addr;
/* More than 16 chars after ";" means the instruction is 8 bytes long. */
inst->size = end - semicolon > 16 ? 8 : 4;
inst->size = inst_end - semicolon > 16 ? 8 : 4;
*addr += inst->size;
if (!(*end))
if (inst_end == end)
break;
disasm = end + 1;
disasm = inst_end + 1;
}
}
@@ -961,7 +984,7 @@ static void si_print_annotated_shader(struct si_shader *shader,
unsigned num_waves,
FILE *f)
{
if (!shader || !shader->binary.disasm_string)
if (!shader)
return;
uint64_t start_addr = shader->bo->gpu_address;
@@ -985,25 +1008,26 @@ static void si_print_annotated_shader(struct si_shader *shader,
*/
unsigned num_inst = 0;
uint64_t inst_addr = start_addr;
struct ac_rtld_binary rtld_binaries[5] = {};
struct si_shader_inst *instructions =
calloc(shader->bo->b.b.width0 / 4, sizeof(struct si_shader_inst));
if (shader->prolog) {
si_add_split_disasm(shader->prolog->binary.disasm_string,
si_add_split_disasm(&rtld_binaries[0], &shader->prolog->binary,
&inst_addr, &num_inst, instructions);
}
if (shader->previous_stage) {
si_add_split_disasm(shader->previous_stage->binary.disasm_string,
si_add_split_disasm(&rtld_binaries[1], &shader->previous_stage->binary,
&inst_addr, &num_inst, instructions);
}
if (shader->prolog2) {
si_add_split_disasm(shader->prolog2->binary.disasm_string,
si_add_split_disasm(&rtld_binaries[2], &shader->prolog2->binary,
&inst_addr, &num_inst, instructions);
}
si_add_split_disasm(shader->binary.disasm_string,
si_add_split_disasm(&rtld_binaries[3], &shader->binary,
&inst_addr, &num_inst, instructions);
if (shader->epilog) {
si_add_split_disasm(shader->epilog->binary.disasm_string,
si_add_split_disasm(&rtld_binaries[4], &shader->epilog->binary,
&inst_addr, &num_inst, instructions);
}
@@ -1041,6 +1065,8 @@ static void si_print_annotated_shader(struct si_shader *shader,
fprintf(f, "\n\n");
free(instructions);
for (unsigned i = 0; i < ARRAY_SIZE(rtld_binaries); ++i)
ac_rtld_close(&rtld_binaries[i]);
}
static void si_dump_annotated_shaders(struct si_context *sctx, FILE *f)