From 360176b671fc7ec30a75eb45557bd2c1fc019fec Mon Sep 17 00:00:00 2001 From: Qiang Yu Date: Tue, 25 Apr 2023 20:50:48 +0800 Subject: [PATCH] aco,radv: support symbol relocation in aco Reviewed-by: Rhys Perry Signed-off-by: Qiang Yu Part-of: --- src/amd/compiler/aco_assembler.cpp | 28 +++++++++++++++++++++++++--- src/amd/compiler/aco_interface.cpp | 14 ++++++++------ src/amd/compiler/aco_interface.h | 3 ++- src/amd/compiler/aco_ir.h | 3 ++- src/amd/compiler/aco_opcodes.py | 1 + src/amd/compiler/aco_shader_info.h | 9 +++++++++ src/amd/compiler/tests/helpers.cpp | 2 +- src/amd/vulkan/radv_shader.c | 3 ++- 8 files changed, 50 insertions(+), 13 deletions(-) diff --git a/src/amd/compiler/aco_assembler.cpp b/src/amd/compiler/aco_assembler.cpp index e6e3de055bd..e05f6dc730b 100644 --- a/src/amd/compiler/aco_assembler.cpp +++ b/src/amd/compiler/aco_assembler.cpp @@ -46,10 +46,12 @@ struct asm_context { enum amd_gfx_level gfx_level; std::vector> branches; std::map constaddrs; + std::vector* 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* 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& 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& 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& out) } unsigned -emit_program(Program* program, std::vector& code) +emit_program(Program* program, std::vector& code, + std::vector* 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) diff --git a/src/amd/compiler/aco_interface.cpp b/src/amd/compiler/aco_interface.cpp index 41f8b0db75e..f011072289e 100644 --- a/src/amd/compiler/aco_interface.cpp +++ b/src/amd/compiler/aco_interface.cpp @@ -236,7 +236,8 @@ aco_compile_shader(const struct aco_compiler_options* options, /* assembly */ std::vector code; - unsigned exec_size = aco::emit_program(program.get(), code); + std::vector 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 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 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 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; diff --git a/src/amd/compiler/aco_interface.h b/src/amd/compiler/aco_interface.h index 817783877ef..a91d7a33d70 100644 --- a/src/amd/compiler/aco_interface.h +++ b/src/amd/compiler/aco_interface.h @@ -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, diff --git a/src/amd/compiler/aco_ir.h b/src/amd/compiler/aco_ir.h index db2158e4ae8..6ae4571abd8 100644 --- a/src/amd/compiler/aco_ir.h +++ b/src/amd/compiler/aco_ir.h @@ -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& code); +unsigned emit_program(Program* program, std::vector& code, + std::vector *symbols); /** * Returns true if print_asm can disassemble the given program for the current build/runtime * configuration diff --git a/src/amd/compiler/aco_opcodes.py b/src/amd/compiler/aco_opcodes.py index 79e0033afab..3fdbf9d2832 100644 --- a/src/amd/compiler/aco_opcodes.py +++ b/src/amd/compiler/aco_opcodes.py @@ -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) diff --git a/src/amd/compiler/aco_shader_info.h b/src/amd/compiler/aco_shader_info.h index 22348b65492..0d1dcd96392 100644 --- a/src/amd/compiler/aco_shader_info.h +++ b/src/amd/compiler/aco_shader_info.h @@ -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 diff --git a/src/amd/compiler/tests/helpers.cpp b/src/amd/compiler/tests/helpers.cpp index 68158abfa79..c5a88447329 100644 --- a/src/amd/compiler/tests/helpers.cpp +++ b/src/amd/compiler/tests/helpers.cpp @@ -254,7 +254,7 @@ void finish_assembler_test() { finish_program(program.get()); std::vector 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 */ diff --git a/src/amd/vulkan/radv_shader.c b/src/amd/vulkan/radv_shader.c index fe3ee0f6b55..f6239057031 100644 --- a/src/amd/vulkan/radv_shader.c +++ b/src/amd/vulkan/radv_shader.c @@ -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;