aco,radv: support symbol relocation in aco

Reviewed-by: Rhys Perry <pendingchaos02@gmail.com>
Signed-off-by: Qiang Yu <yuq825@gmail.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/22727>
This commit is contained in:
Qiang Yu 2023-04-25 20:50:48 +08:00
parent 3fc4ddd628
commit 360176b671
8 changed files with 50 additions and 13 deletions

View file

@ -46,10 +46,12 @@ struct asm_context {
enum amd_gfx_level gfx_level;
std::vector<std::pair<int, SOPP_instruction*>> branches;
std::map<unsigned, constaddr_info> constaddrs;
std::vector<struct aco_symbol>* symbols;
const int16_t* opcode;
// TODO: keep track of branch instructions referring blocks
// and, when emitting the block, correct the offset in instr
asm_context(Program* program_) : program(program_), gfx_level(program->gfx_level)
asm_context(Program* program_, std::vector<struct aco_symbol>* symbols_)
: program(program_), gfx_level(program->gfx_level), symbols(symbols_)
{
if (gfx_level <= GFX7)
opcode = &instr_info.opcode_gfx7[0];
@ -136,6 +138,18 @@ emit_instruction(asm_context& ctx, std::vector<uint32_t>& out, Instruction* inst
assert(instr->operands[1].isConstant());
/* in case it's an inline constant, make it a literal */
instr->operands[1] = Operand::literal32(instr->operands[1].constantValue());
} else if (instr->opcode == aco_opcode::p_load_symbol) {
assert(instr->operands[0].isConstant());
assert(ctx.symbols);
struct aco_symbol info;
info.id = (enum aco_symbol_id)instr->operands[0].constantValue();
info.offset = out.size() + 1;
ctx.symbols->push_back(info);
instr->opcode = aco_opcode::s_mov_b32;
/* in case it's an inline constant, make it a literal */
instr->operands[0] = Operand::literal32(0);
}
/* Promote VOP12C to VOP3 if necessary. */
@ -1036,6 +1050,13 @@ insert_code(asm_context& ctx, std::vector<uint32_t>& out, unsigned insert_before
if (info.add_literal >= insert_before)
info.add_literal += insert_count;
}
if (ctx.symbols) {
for (auto& symbol : *ctx.symbols) {
if (symbol.offset >= insert_before)
symbol.offset += insert_count;
}
}
}
static void
@ -1171,9 +1192,10 @@ fix_constaddrs(asm_context& ctx, std::vector<uint32_t>& out)
}
unsigned
emit_program(Program* program, std::vector<uint32_t>& code)
emit_program(Program* program, std::vector<uint32_t>& code,
std::vector<struct aco_symbol>* symbols)
{
asm_context ctx(program);
asm_context ctx(program, symbols);
if (program->stage.hw == HWStage::VS || program->stage.hw == HWStage::FS ||
program->stage.hw == HWStage::NGG)

View file

@ -236,7 +236,8 @@ aco_compile_shader(const struct aco_compiler_options* options,
/* assembly */
std::vector<uint32_t> code;
unsigned exec_size = aco::emit_program(program.get(), code);
std::vector<struct aco_symbol> symbols;
unsigned exec_size = aco::emit_program(program.get(), code, &symbols);
if (program->collect_statistics)
aco::collect_postasm_stats(program.get(), code);
@ -252,7 +253,8 @@ aco_compile_shader(const struct aco_compiler_options* options,
stats_size = aco_num_statistics * sizeof(uint32_t);
(*build_binary)(binary, &config, llvm_ir.c_str(), llvm_ir.size(), disasm.c_str(), disasm.size(),
program->statistics, stats_size, exec_size, code.data(), code.size());
program->statistics, stats_size, exec_size, code.data(), code.size(),
symbols.data(), symbols.size());
}
void
@ -282,7 +284,7 @@ aco_compile_rt_prolog(const struct aco_compiler_options* options,
/* assembly */
std::vector<uint32_t> code;
code.reserve(align(program->blocks[0].instructions.size() * 2, 16));
unsigned exec_size = aco::emit_program(program.get(), code);
unsigned exec_size = aco::emit_program(program.get(), code, NULL);
bool get_disasm = options->dump_shader || options->record_ir;
@ -291,7 +293,7 @@ aco_compile_rt_prolog(const struct aco_compiler_options* options,
disasm = get_disasm_string(program.get(), code, exec_size);
(*build_prolog)(binary, &config, NULL, 0, disasm.c_str(), disasm.size(), program->statistics, 0,
exec_size, code.data(), code.size());
exec_size, code.data(), code.size(), NULL, 0);
}
void
@ -319,7 +321,7 @@ aco_compile_vs_prolog(const struct aco_compiler_options* options,
/* assembly */
std::vector<uint32_t> code;
code.reserve(align(program->blocks[0].instructions.size() * 2, 16));
unsigned exec_size = aco::emit_program(program.get(), code);
unsigned exec_size = aco::emit_program(program.get(), code, NULL);
bool get_disasm = options->dump_shader || options->record_ir;
@ -361,7 +363,7 @@ aco_compile_ps_epilog(const struct aco_compiler_options* options,
/* assembly */
std::vector<uint32_t> code;
unsigned exec_size = aco::emit_program(program.get(), code);
unsigned exec_size = aco::emit_program(program.get(), code, NULL);
bool get_disasm = options->dump_shader || options->record_ir;

View file

@ -46,7 +46,8 @@ struct aco_compiler_statistic_info {
typedef void(aco_callback)(void** priv_ptr, const struct ac_shader_config* config,
const char* llvm_ir_str, unsigned llvm_ir_size, const char* disasm_str,
unsigned disasm_size, uint32_t* statistics, uint32_t stats_size,
uint32_t exec_size, const uint32_t* code, uint32_t code_dw);
uint32_t exec_size, const uint32_t* code, uint32_t code_dw,
const struct aco_symbol *symbols, unsigned num_symbols);
typedef void (aco_shader_part_callback)(void **priv_ptr,
uint32_t num_sgprs,

View file

@ -2226,7 +2226,8 @@ void insert_wait_states(Program* program);
bool dealloc_vgprs(Program* program);
void insert_NOPs(Program* program);
void form_hard_clauses(Program* program);
unsigned emit_program(Program* program, std::vector<uint32_t>& code);
unsigned emit_program(Program* program, std::vector<uint32_t>& code,
std::vector<struct aco_symbol> *symbols);
/**
* Returns true if print_asm can disassemble the given program for the current build/runtime
* configuration

View file

@ -530,6 +530,7 @@ SOP1 = {
( -1, -1, -1, -1, -1, 0x4d, "s_sendmsg_rtn_b64"),
# actually a pseudo-instruction. it's lowered to SALU during assembly though, so it's useful to identify it as a SOP1.
( -1, -1, -1, -1, -1, -1, "p_constaddr_getpc"),
( -1, -1, -1, -1, -1, -1, "p_load_symbol"),
}
for (gfx6, gfx7, gfx8, gfx9, gfx10, gfx11, name, cls) in default_class(SOP1, InstrClass.Salu):
opcode(name, gfx7, gfx9, gfx10, gfx11, Format.SOP1, cls)

View file

@ -160,6 +160,15 @@ enum aco_statistic {
aco_num_statistics
};
enum aco_symbol_id {
aco_symbol_invalid,
};
struct aco_symbol {
enum aco_symbol_id id;
unsigned offset;
};
#ifdef __cplusplus
}
#endif

View file

@ -254,7 +254,7 @@ void finish_assembler_test()
{
finish_program(program.get());
std::vector<uint32_t> binary;
unsigned exec_size = emit_program(program.get(), binary);
unsigned exec_size = emit_program(program.get(), binary, NULL);
/* we could use CLRX for disassembly but that would require it to be
* installed */

View file

@ -2070,7 +2070,8 @@ static void
radv_aco_build_shader_binary(void **bin, const struct ac_shader_config *config,
const char *llvm_ir_str, unsigned llvm_ir_size, const char *disasm_str,
unsigned disasm_size, uint32_t *statistics, uint32_t stats_size,
uint32_t exec_size, const uint32_t *code, uint32_t code_dw)
uint32_t exec_size, const uint32_t *code, uint32_t code_dw,
const struct aco_symbol *symbols, unsigned num_symbols)
{
struct radv_shader_binary **binary = (struct radv_shader_binary **)bin;
size_t size = llvm_ir_size;