Module: Mesa
Branch: main
Commit: 360176b671fc7ec30a75eb45557bd2c1fc019fec
URL:    
http://cgit.freedesktop.org/mesa/mesa/commit/?id=360176b671fc7ec30a75eb45557bd2c1fc019fec

Author: Qiang Yu <[email protected]>
Date:   Tue Apr 25 20:50:48 2023 +0800

aco,radv: support symbol relocation in aco

Reviewed-by: Rhys Perry <[email protected]>
Signed-off-by: Qiang Yu <[email protected]>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/22727>

---

 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<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)
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<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;
 
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<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
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<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 */
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;

Reply via email to