[Mesa-dev] [PATCH 10/10] radeonsi: use the new run-time linker for shaders

Nicolai Hähnle nhaehnle at gmail.com
Fri May 3 11:18:29 UTC 2019


From: Nicolai Hähnle <nicolai.haehnle at amd.com>

---
 src/gallium/drivers/radeonsi/si_compute.c     |  63 ++--
 src/gallium/drivers/radeonsi/si_debug.c       |  74 +++--
 src/gallium/drivers/radeonsi/si_pipe.c        |   2 +-
 src/gallium/drivers/radeonsi/si_pipe.h        |   2 +-
 src/gallium/drivers/radeonsi/si_shader.c      | 291 +++++++++---------
 src/gallium/drivers/radeonsi/si_shader.h      |  19 +-
 .../drivers/radeonsi/si_shader_internal.h     |   3 +-
 .../drivers/radeonsi/si_shader_tgsi_setup.c   |  14 +-
 .../drivers/radeonsi/si_state_shaders.c       |  39 +--
 9 files changed, 270 insertions(+), 237 deletions(-)

diff --git a/src/gallium/drivers/radeonsi/si_compute.c b/src/gallium/drivers/radeonsi/si_compute.c
index 2899ee146d4..e4ef138db33 100644
--- a/src/gallium/drivers/radeonsi/si_compute.c
+++ b/src/gallium/drivers/radeonsi/si_compute.c
@@ -21,20 +21,21 @@
  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
  * USE OR OTHER DEALINGS IN THE SOFTWARE.
  *
  */
 
 #include "tgsi/tgsi_parse.h"
 #include "util/u_async_debug.h"
 #include "util/u_memory.h"
 #include "util/u_upload_mgr.h"
 
+#include "ac_rtld.h"
 #include "amd_kernel_code_t.h"
 #include "si_build_pm4.h"
 #include "si_compute.h"
 
 #define COMPUTE_DBG(sscreen, fmt, args...) \
 	do { \
 		if ((sscreen->debug_flags & DBG(COMPUTE))) fprintf(stderr, fmt, ##args); \
 	} while (0);
 
 struct dispatch_packet {
@@ -54,22 +55,40 @@ struct dispatch_packet {
 	uint64_t reserved2;
 };
 
 static const amd_kernel_code_t *si_compute_get_code_object(
 	const struct si_compute *program,
 	uint64_t symbol_offset)
 {
 	if (!program->use_code_object_v2) {
 		return NULL;
 	}
-	return (const amd_kernel_code_t*)
-		(program->shader.binary.code + symbol_offset);
+
+	struct ac_rtld_binary rtld;
+	if (!ac_rtld_open(&rtld, 1, &program->shader.binary.elf_buffer,
+			  &program->shader.binary.elf_size))
+		return NULL;
+
+	const amd_kernel_code_t *result = NULL;
+	const char *text;
+	size_t size;
+	if (!ac_rtld_get_section_by_name(&rtld, ".text", &text, &size))
+		goto out;
+
+	if (symbol_offset + sizeof(amd_kernel_code_t) > size)
+		goto out;
+
+	result = (const amd_kernel_code_t*)(text + symbol_offset);
+
+out:
+	ac_rtld_close(&rtld);
+	return result;
 }
 
 static void code_object_to_config(const amd_kernel_code_t *code_object,
 				  struct ac_shader_config *out_config) {
 
 	uint32_t rsrc1 = code_object->compute_pgm_resource_registers;
 	uint32_t rsrc2 = code_object->compute_pgm_resource_registers >> 32;
 	out_config->num_sgprs = code_object->wavefront_sgpr_count;
 	out_config->num_vgprs = code_object->workitem_vgpr_count;
 	out_config->float_mode = G_00B028_FLOAT_MODE(rsrc1);
@@ -137,21 +156,21 @@ static void si_create_compute_state_async(void *job, int thread_index)
 	mtx_lock(&sscreen->shader_cache_mutex);
 
 	if (ir_binary &&
 	    si_shader_cache_load_shader(sscreen, ir_binary, shader)) {
 		mtx_unlock(&sscreen->shader_cache_mutex);
 
 		si_shader_dump_stats_for_shader_db(shader, debug);
 		si_shader_dump(sscreen, shader, debug, PIPE_SHADER_COMPUTE,
 			       stderr, true);
 
-		if (!si_shader_binary_upload(sscreen, shader))
+		if (!si_shader_binary_upload(sscreen, shader, 0))
 			program->shader.compilation_failed = true;
 	} else {
 		mtx_unlock(&sscreen->shader_cache_mutex);
 
 		if (!si_shader_create(sscreen, compiler, &program->shader, debug)) {
 			program->shader.compilation_failed = true;
 
 			if (program->ir_type == PIPE_SHADER_IR_TGSI)
 				FREE(program->ir.tgsi);
 			program->shader.selector = NULL;
@@ -229,39 +248,37 @@ static void *si_create_compute_state(
 		si_schedule_initial_compile(sctx, PIPE_SHADER_COMPUTE,
 					    &program->ready,
 					    &program->compiler_ctx_state,
 					    program, si_create_compute_state_async);
 	} else {
 		const struct pipe_llvm_program_header *header;
 		const char *code;
 		header = cso->prog;
 		code = cso->prog + sizeof(struct pipe_llvm_program_header);
 
-		ac_elf_read(code, header->num_bytes, &program->shader.binary);
-		if (program->use_code_object_v2) {
-			const amd_kernel_code_t *code_object =
-				si_compute_get_code_object(program, 0);
-			code_object_to_config(code_object, &program->shader.config);
-			if (program->shader.binary.reloc_count != 0) {
-				fprintf(stderr, "Error: %d unsupported relocations\n",
-					program->shader.binary.reloc_count);
-				FREE(program);
-				return NULL;
-			}
-		} else {
-			ac_shader_binary_read_config(&program->shader.binary,
-				     &program->shader.config, 0, false);
+		program->shader.binary.elf_size = header->num_bytes;
+		program->shader.binary.elf_buffer = malloc(header->num_bytes);
+		if (!program->shader.binary.elf_buffer) {
+			FREE(program);
+			return NULL;
 		}
+		memcpy((void *)program->shader.binary.elf_buffer, code, header->num_bytes);
+
+		const amd_kernel_code_t *code_object =
+			si_compute_get_code_object(program, 0);
+		code_object_to_config(code_object, &program->shader.config);
+
 		si_shader_dump(sctx->screen, &program->shader, &sctx->debug,
 			       PIPE_SHADER_COMPUTE, stderr, true);
-		if (!si_shader_binary_upload(sctx->screen, &program->shader)) {
+		if (!si_shader_binary_upload(sctx->screen, &program->shader, 0)) {
 			fprintf(stderr, "LLVM failed to upload shader\n");
+			free((void *)program->shader.binary.elf_buffer);
 			FREE(program);
 			return NULL;
 		}
 	}
 
 	return program;
 }
 
 static void si_bind_compute_state(struct pipe_context *ctx, void *state)
 {
@@ -386,23 +403,21 @@ static bool si_setup_compute_scratch_buffer(struct si_context *sctx,
 						 PIPE_USAGE_DEFAULT,
 						 scratch_needed, 256);
 
 		if (!sctx->compute_scratch_buffer)
 			return false;
 	}
 
 	if (sctx->compute_scratch_buffer != shader->scratch_bo && scratch_needed) {
 		uint64_t scratch_va = sctx->compute_scratch_buffer->gpu_address;
 
-		si_shader_apply_scratch_relocs(shader, scratch_va);
-
-		if (!si_shader_binary_upload(sctx->screen, shader))
+		if (!si_shader_binary_upload(sctx->screen, shader, scratch_va))
 			return false;
 
 		si_resource_reference(&shader->scratch_bo,
 		                        sctx->compute_scratch_buffer);
 	}
 
 	return true;
 }
 
 static bool si_switch_compute_shader(struct si_context *sctx,
@@ -419,25 +434,21 @@ static bool si_switch_compute_shader(struct si_context *sctx,
 	if (sctx->cs_shader_state.emitted_program == program &&
 	    sctx->cs_shader_state.offset == offset)
 		return true;
 
 	if (program->ir_type != PIPE_SHADER_IR_NATIVE) {
 		config = &shader->config;
 	} else {
 		unsigned lds_blocks;
 
 		config = &inline_config;
-		if (code_object) {
-			code_object_to_config(code_object, config);
-		} else {
-			ac_shader_binary_read_config(&shader->binary, config, offset, false);
-		}
+		code_object_to_config(code_object, config);
 
 		lds_blocks = config->lds_size;
 		/* XXX: We are over allocating LDS.  For SI, the shader reports
 		* LDS in blocks of 256 bytes, so if there are 4 bytes lds
 		* allocated in the shader and 4 bytes allocated by the state
 		* tracker, then we will set LDS_SIZE to 512 bytes rather than 256.
 		*/
 		if (sctx->chip_class <= SI) {
 			lds_blocks += align(program->local_size, 256) >> 8;
 		} else {
diff --git a/src/gallium/drivers/radeonsi/si_debug.c b/src/gallium/drivers/radeonsi/si_debug.c
index c40dcd0b5d6..ae7ac2f0442 100644
--- a/src/gallium/drivers/radeonsi/si_debug.c
+++ b/src/gallium/drivers/radeonsi/si_debug.c
@@ -26,20 +26,21 @@
 #include "si_compute.h"
 #include "sid.h"
 #include "gfx9d.h"
 #include "sid_tables.h"
 #include "driver_ddebug/dd_util.h"
 #include "util/u_dump.h"
 #include "util/u_log.h"
 #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);
 
 DEBUG_GET_ONCE_OPTION(replace_shaders, "RADEON_REPLACE_SHADERS", NULL)
 
 /**
  * Store a linearized copy of all chunks of \p cs together with the buffer
  * list in \p saved.
  */
@@ -195,29 +196,30 @@ static void si_dump_compute_shader(struct si_context *ctx,
 	chunk->ctx = ctx;
 	chunk->processor = PIPE_SHADER_COMPUTE;
 	chunk->shader = &state->program->shader;
 	si_compute_reference(&chunk->program, state->program);
 	u_log_chunk(log, &si_log_chunk_type_shader, chunk);
 }
 
 /**
  * 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)
 		return false;
 
 	while (*p) {
 		unsigned long i;
 		char *endp;
 		i = strtoul(p, &endp, 0);
 
@@ -259,37 +261,39 @@ bool si_replace_shader(unsigned num, struct ac_shader_binary *binary)
 	if (fseek(f, 0, SEEK_END) != 0)
 		goto file_error;
 
 	filesize = ftell(f);
 	if (filesize < 0)
 		goto file_error;
 
 	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;
 
 file_error:
 	perror("radeonsi: reading shader");
 	goto out_close;
 }
 
 /* Parsed IBs are difficult to read without colors. Use "less -R file" to
  * read them, or use "aha -b -f file" to convert them to html.
@@ -888,60 +892,79 @@ static void si_dump_compute_descriptors(struct si_context *sctx,
 }
 
 struct si_shader_inst {
 	const char *text; /* start of disassembly for this instruction */
 	unsigned textlen;
 	unsigned size;   /* instruction size = 4 or 8 */
 	uint64_t addr; /* instruction address */
 };
 
 /**
- * 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;
+	uint64_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;
 	}
 }
 
 /* If the shader is being executed, print its asm instructions, and annotate
  * those that are being executed right now with information about waves that
  * execute them. This is most useful during a GPU hang.
  */
 static void si_print_annotated_shader(struct si_shader *shader,
 				      struct ac_wave_info *waves,
 				      unsigned num_waves,
 				      FILE *f)
 {
-	if (!shader || !shader->binary.disasm_string)
+	if (!shader)
 		return;
 
 	uint64_t start_addr = shader->bo->gpu_address;
 	uint64_t end_addr = start_addr + shader->bo->b.b.width0;
 	unsigned i;
 
 	/* See if any wave executes the shader. */
 	for (i = 0; i < num_waves; i++) {
 		if (start_addr <= waves[i].pc && waves[i].pc <= end_addr)
 			break;
@@ -951,39 +974,40 @@ static void si_print_annotated_shader(struct si_shader *shader,
 
 	/* Remember the first found wave. The waves are sorted according to PC. */
 	waves = &waves[i];
 	num_waves -= i;
 
 	/* Get the list of instructions.
 	 * Buffer size / 4 is the upper bound of the instruction count.
 	 */
 	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);
 	}
 
 	fprintf(f, COLOR_YELLOW "%s - annotated disassembly:" COLOR_RESET "\n",
 		si_get_shader_name(shader, shader->selector->type));
 
 	/* Print instructions with annotations. */
 	for (i = 0; i < num_inst; i++) {
 		struct si_shader_inst *inst = &instructions[i];
 
@@ -1007,20 +1031,22 @@ static void si_print_annotated_shader(struct si_shader *shader,
 			}
 
 			waves->matched = true;
 			waves = &waves[1];
 			num_waves--;
 		}
 	}
 
 	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)
 {
 	struct ac_wave_info waves[AC_MAX_WAVES_PER_CHIP];
 	unsigned num_waves = ac_get_wave_info(waves);
 
 	fprintf(f, COLOR_CYAN "The number of active waves = %u" COLOR_RESET
 		"\n\n", num_waves);
 
diff --git a/src/gallium/drivers/radeonsi/si_pipe.c b/src/gallium/drivers/radeonsi/si_pipe.c
index aaf5138a3a2..795aef97d73 100644
--- a/src/gallium/drivers/radeonsi/si_pipe.c
+++ b/src/gallium/drivers/radeonsi/si_pipe.c
@@ -723,21 +723,21 @@ static void si_destroy_screen(struct pipe_screen* pscreen)
 
 	for (i = 0; i < ARRAY_SIZE(sscreen->compiler_lowp); i++)
 		si_destroy_compiler(&sscreen->compiler_lowp[i]);
 
 	/* Free shader parts. */
 	for (i = 0; i < ARRAY_SIZE(parts); i++) {
 		while (parts[i]) {
 			struct si_shader_part *part = parts[i];
 
 			parts[i] = part->next;
-			ac_shader_binary_clean(&part->binary);
+			si_shader_binary_clean(&part->binary);
 			FREE(part);
 		}
 	}
 	mtx_destroy(&sscreen->shader_parts_mutex);
 	si_destroy_shader_cache(sscreen);
 
 	si_destroy_perfcounters(sscreen);
 	si_gpu_load_kill_thread(sscreen);
 
 	mtx_destroy(&sscreen->gpu_load_mutex);
diff --git a/src/gallium/drivers/radeonsi/si_pipe.h b/src/gallium/drivers/radeonsi/si_pipe.h
index 695827c9dd7..c6a2e7179e8 100644
--- a/src/gallium/drivers/radeonsi/si_pipe.h
+++ b/src/gallium/drivers/radeonsi/si_pipe.h
@@ -1249,21 +1249,21 @@ void si_save_cs(struct radeon_winsys *ws, struct radeon_cmdbuf *cs,
 		struct radeon_saved_cs *saved, bool get_buffer_list);
 void si_clear_saved_cs(struct radeon_saved_cs *saved);
 void si_destroy_saved_cs(struct si_saved_cs *scs);
 void si_auto_log_cs(void *data, struct u_log_context *log);
 void si_log_hw_flush(struct si_context *sctx);
 void si_log_draw_state(struct si_context *sctx, struct u_log_context *log);
 void si_log_compute_state(struct si_context *sctx, struct u_log_context *log);
 void si_init_debug_functions(struct si_context *sctx);
 void si_check_vm_faults(struct si_context *sctx,
 			struct radeon_saved_cs *saved, enum ring_type ring);
-bool si_replace_shader(unsigned num, struct ac_shader_binary *binary);
+bool si_replace_shader(unsigned num, struct si_shader_binary *binary);
 
 /* si_dma.c */
 void si_init_dma_functions(struct si_context *sctx);
 
 /* si_dma_cs.c */
 void si_dma_emit_timestamp(struct si_context *sctx, struct si_resource *dst,
 			   uint64_t offset);
 void si_sdma_clear_buffer(struct si_context *sctx, struct pipe_resource *dst,
 			  uint64_t offset, uint64_t size, unsigned clear_value);
 void si_need_dma_space(struct si_context *ctx, unsigned num_dw,
diff --git a/src/gallium/drivers/radeonsi/si_shader.c b/src/gallium/drivers/radeonsi/si_shader.c
index c457ca12b9a..38658942007 100644
--- a/src/gallium/drivers/radeonsi/si_shader.c
+++ b/src/gallium/drivers/radeonsi/si_shader.c
@@ -21,22 +21,24 @@
  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
  * USE OR OTHER DEALINGS IN THE SOFTWARE.
  */
 
 #include "util/u_memory.h"
 #include "util/u_string.h"
 #include "tgsi/tgsi_build.h"
 #include "tgsi/tgsi_util.h"
 #include "tgsi/tgsi_dump.h"
 
+#include "ac_binary.h"
 #include "ac_exp_param.h"
 #include "ac_shader_util.h"
+#include "ac_rtld.h"
 #include "ac_llvm_util.h"
 #include "si_shader_internal.h"
 #include "si_pipe.h"
 #include "sid.h"
 
 #include "compiler/nir/nir.h"
 
 static const char scratch_rsrc_dword0_symbol[] =
 	"SCRATCH_RSRC_DWORD0";
 
@@ -4962,182 +4964,169 @@ static void si_llvm_emit_polygon_stipple(struct si_shader_context *ctx,
 	/* The stipple pattern is 32x32, each row has 32 bits. */
 	offset = LLVMBuildMul(builder, address[1],
 			      LLVMConstInt(ctx->i32, 4, 0), "");
 	row = buffer_load_const(ctx, desc, offset);
 	row = ac_to_integer(&ctx->ac, row);
 	bit = LLVMBuildLShr(builder, row, address[0], "");
 	bit = LLVMBuildTrunc(builder, bit, ctx->i1, "");
 	ac_build_kill_if_false(&ctx->ac, bit);
 }
 
-void si_shader_apply_scratch_relocs(struct si_shader *shader,
-				    uint64_t scratch_va)
-{
-	unsigned i;
-	uint32_t scratch_rsrc_dword0 = scratch_va;
-	uint32_t scratch_rsrc_dword1 =
-		S_008F04_BASE_ADDRESS_HI(scratch_va >> 32);
-
-	/* Enable scratch coalescing. */
-	scratch_rsrc_dword1 |= S_008F04_SWIZZLE_ENABLE(1);
-
-	for (i = 0 ; i < shader->binary.reloc_count; i++) {
-		const struct ac_shader_reloc *reloc =
-					&shader->binary.relocs[i];
-		if (!strcmp(scratch_rsrc_dword0_symbol, reloc->name)) {
-			util_memcpy_cpu_to_le32(shader->binary.code + reloc->offset,
-			&scratch_rsrc_dword0, 4);
-		} else if (!strcmp(scratch_rsrc_dword1_symbol, reloc->name)) {
-			util_memcpy_cpu_to_le32(shader->binary.code + reloc->offset,
-			&scratch_rsrc_dword1, 4);
-		}
-	}
-}
-
 /* For the UMR disassembler. */
 #define DEBUGGER_END_OF_CODE_MARKER	0xbf9f0000 /* invalid instruction */
 #define DEBUGGER_NUM_MARKERS		5
 
+static bool si_shader_binary_open(const struct si_shader *shader,
+				  struct ac_rtld_binary *rtld)
+{
+	const char *part_elfs[5];
+	uint64_t part_sizes[5];
+	unsigned num_parts = 0;
+
+#define add_part(shader_or_part) \
+	if (shader_or_part) { \
+		part_elfs[num_parts] = (shader_or_part)->binary.elf_buffer; \
+		part_sizes[num_parts] = (shader_or_part)->binary.elf_size; \
+		num_parts++; \
+	}
+
+	add_part(shader->prolog);
+	add_part(shader->previous_stage);
+	add_part(shader->prolog2);
+	add_part(shader);
+	add_part(shader->epilog);
+
+#undef add_part
+
+	return ac_rtld_open(rtld, num_parts, part_elfs, part_sizes);
+}
+
 static unsigned si_get_shader_binary_size(const struct si_shader *shader)
 {
-	unsigned size = shader->binary.code_size;
-
-	if (shader->prolog)
-		size += shader->prolog->binary.code_size;
-	if (shader->previous_stage)
-		size += shader->previous_stage->binary.code_size;
-	if (shader->prolog2)
-		size += shader->prolog2->binary.code_size;
-	if (shader->epilog)
-		size += shader->epilog->binary.code_size;
-	return size + DEBUGGER_NUM_MARKERS * 4;
-}
-
-bool si_shader_binary_upload(struct si_screen *sscreen, struct si_shader *shader)
-{
-	const struct ac_shader_binary *prolog =
-		shader->prolog ? &shader->prolog->binary : NULL;
-	const struct ac_shader_binary *previous_stage =
-		shader->previous_stage ? &shader->previous_stage->binary : NULL;
-	const struct ac_shader_binary *prolog2 =
-		shader->prolog2 ? &shader->prolog2->binary : NULL;
-	const struct ac_shader_binary *epilog =
-		shader->epilog ? &shader->epilog->binary : NULL;
-	const struct ac_shader_binary *mainb = &shader->binary;
-	unsigned bo_size = si_get_shader_binary_size(shader) +
-			   (!epilog ? mainb->rodata_size : 0);
-	unsigned char *ptr;
-
-	assert(!prolog || !prolog->rodata_size);
-	assert(!previous_stage || !previous_stage->rodata_size);
-	assert(!prolog2 || !prolog2->rodata_size);
-	assert((!prolog && !previous_stage && !prolog2 && !epilog) ||
-	       !mainb->rodata_size);
-	assert(!epilog || !epilog->rodata_size);
+	struct ac_rtld_binary rtld;
+	si_shader_binary_open(shader, &rtld);
+	return rtld.rx_size;
+}
+
+
+static bool si_get_external_symbol(void *data, const char *name, uint64_t *value)
+{
+	uint64_t *scratch_va = data;
+
+	if (!strcmp(scratch_rsrc_dword0_symbol, name)) {
+		*value = (uint32_t)*scratch_va;
+		return true;
+	}
+	if (!strcmp(scratch_rsrc_dword1_symbol, name)) {
+		/* Enable scratch coalescing. */
+		*value = S_008F04_BASE_ADDRESS_HI(*scratch_va >> 32) |
+			 S_008F04_SWIZZLE_ENABLE(1);
+		if (HAVE_LLVM < 0x0800) {
+			/* Old LLVM created an R_ABS32_HI relocation for
+			 * this symbol. */
+			*value <<= 32;
+		}
+		return true;
+	}
+
+	return false;
+}
+
+bool si_shader_binary_upload(struct si_screen *sscreen, struct si_shader *shader,
+			     uint64_t scratch_va)
+{
+	struct ac_rtld_binary binary;
+	if (!si_shader_binary_open(shader, &binary))
+		return false;
 
 	si_resource_reference(&shader->bo, NULL);
 	shader->bo = si_aligned_buffer_create(&sscreen->b,
 					      sscreen->cpdma_prefetch_writes_memory ?
 						0 : SI_RESOURCE_FLAG_READ_ONLY,
                                               PIPE_USAGE_IMMUTABLE,
-                                              align(bo_size, SI_CPDMA_ALIGNMENT),
+                                              align(binary.rx_size, SI_CPDMA_ALIGNMENT),
                                               256);
 	if (!shader->bo)
 		return false;
 
 	/* Upload. */
-	ptr = sscreen->ws->buffer_map(shader->bo->buf, NULL,
+	struct ac_rtld_upload_info u;
+	u.binary = &binary;
+	u.get_external_symbol = si_get_external_symbol;
+	u.cb_data = &scratch_va;
+	u.rx_va = shader->bo->gpu_address;
+	u.rx_ptr = sscreen->ws->buffer_map(shader->bo->buf, NULL,
 					PIPE_TRANSFER_READ_WRITE |
 					PIPE_TRANSFER_UNSYNCHRONIZED |
 					RADEON_TRANSFER_TEMPORARY);
+	if (!u.rx_ptr)
+		return false;
 
-	/* Don't use util_memcpy_cpu_to_le32. LLVM binaries are
-	 * endian-independent. */
-	if (prolog) {
-		memcpy(ptr, prolog->code, prolog->code_size);
-		ptr += prolog->code_size;
-	}
-	if (previous_stage) {
-		memcpy(ptr, previous_stage->code, previous_stage->code_size);
-		ptr += previous_stage->code_size;
-	}
-	if (prolog2) {
-		memcpy(ptr, prolog2->code, prolog2->code_size);
-		ptr += prolog2->code_size;
-	}
-
-	memcpy(ptr, mainb->code, mainb->code_size);
-	ptr += mainb->code_size;
-
-	if (epilog) {
-		memcpy(ptr, epilog->code, epilog->code_size);
-		ptr += epilog->code_size;
-	} else if (mainb->rodata_size > 0) {
-		memcpy(ptr, mainb->rodata, mainb->rodata_size);
-		ptr += mainb->rodata_size;
-	}
-
-	/* Add end-of-code markers for the UMR disassembler. */
-	uint32_t *ptr32 = (uint32_t*)ptr;
-	for (unsigned i = 0; i < DEBUGGER_NUM_MARKERS; i++)
-		ptr32[i] = DEBUGGER_END_OF_CODE_MARKER;
+	bool ok = ac_rtld_upload(&u);
 
 	sscreen->ws->buffer_unmap(shader->bo->buf);
-	return true;
+	return ok;
 }
 
-static void si_shader_dump_disassembly(const struct ac_shader_binary *binary,
+static void si_shader_dump_disassembly(const struct si_shader_binary *binary,
 				       struct pipe_debug_callback *debug,
 				       const char *name, FILE *file)
 {
-	char *line, *p;
-	unsigned i, count;
+	struct ac_rtld_binary rtld_binary;
 
-	if (binary->disasm_string) {
-		fprintf(file, "Shader %s disassembly:\n", name);
-		fprintf(file, "%s", binary->disasm_string);
+	if (!ac_rtld_open(&rtld_binary, 1, &binary->elf_buffer, &binary->elf_size))
+		return;
 
-		if (debug && debug->debug_message) {
-			/* Very long debug messages are cut off, so send the
-			 * disassembly one line at a time. This causes more
-			 * overhead, but on the plus side it simplifies
-			 * parsing of resulting logs.
-			 */
-			pipe_debug_message(debug, SHADER_INFO,
-					   "Shader Disassembly Begin");
+	const char *disasm;
+	uint64_t nbytes;
 
-			line = binary->disasm_string;
-			while (*line) {
-				p = util_strchrnul(line, '\n');
-				count = p - line;
+	if (!ac_rtld_get_section_by_name(&rtld_binary, ".AMDGPU.disasm", &disasm, &nbytes))
+		goto out;
 
-				if (count) {
-					pipe_debug_message(debug, SHADER_INFO,
-							   "%.*s", count, line);
-				}
+	fprintf(file, "Shader %s disassembly:\n", name);
+	if (nbytes > INT_MAX) {
+		fprintf(file, "too long\n");
+		goto out;
+	}
 
-				if (!*p)
-					break;
-				line = p + 1;
+	fprintf(file, "%*s", (int)nbytes, disasm);
+
+	if (debug && debug->debug_message) {
+		/* Very long debug messages are cut off, so send the
+		 * disassembly one line at a time. This causes more
+		 * overhead, but on the plus side it simplifies
+		 * parsing of resulting logs.
+		 */
+		pipe_debug_message(debug, SHADER_INFO,
+				   "Shader Disassembly Begin");
+
+		uint64_t line = 0;
+		while (line < nbytes) {
+			int count = nbytes - line;
+			const char *nl = memchr(disasm + line, '\n', nbytes - line);
+			if (nl)
+				count = nl - disasm;
+
+			if (count) {
+				pipe_debug_message(debug, SHADER_INFO,
+						   "%.*s", count, disasm + line);
 			}
 
-			pipe_debug_message(debug, SHADER_INFO,
-					   "Shader Disassembly End");
-		}
-	} else {
-		fprintf(file, "Shader %s binary:\n", name);
-		for (i = 0; i < binary->code_size; i += 4) {
-			fprintf(file, "@0x%x: %02x%02x%02x%02x\n", i,
-				binary->code[i + 3], binary->code[i + 2],
-				binary->code[i + 1], binary->code[i]);
+			line += count + 1;
 		}
+
+		pipe_debug_message(debug, SHADER_INFO,
+				   "Shader Disassembly End");
 	}
+
+out:
+	ac_rtld_close(&rtld_binary);
 }
 
 static void si_calculate_max_simd_waves(struct si_shader *shader)
 {
 	struct si_screen *sscreen = shader->selector->screen;
 	struct ac_shader_config *conf = &shader->config;
 	unsigned num_inputs = shader->selector->info.num_inputs;
 	unsigned lds_increment = sscreen->info.chip_class >= CIK ? 512 : 256;
 	unsigned lds_per_wave = 0;
 	unsigned max_simd_waves;
@@ -5313,90 +5302,86 @@ void si_shader_dump(struct si_screen *sscreen, const struct si_shader *shader,
 		if (shader->epilog)
 			si_shader_dump_disassembly(&shader->epilog->binary,
 						   debug, "epilog", file);
 		fprintf(file, "\n");
 	}
 
 	si_shader_dump_stats(sscreen, shader, processor, file,
 			     check_debug_option);
 }
 
+bool si_shader_binary_read_config(struct si_shader_binary *binary,
+				  struct ac_shader_config *conf)
+{
+	struct ac_rtld_binary rtld;
+	if (!ac_rtld_open(&rtld, 1, &binary->elf_buffer, &binary->elf_size))
+		return false;
+
+	bool ok = ac_rtld_read_config(&rtld, conf);
+
+	ac_rtld_close(&rtld);
+	return ok;
+}
+
 static int si_compile_llvm(struct si_screen *sscreen,
-			   struct ac_shader_binary *binary,
+			   struct si_shader_binary *binary,
 			   struct ac_shader_config *conf,
 			   struct ac_llvm_compiler *compiler,
 			   LLVMModuleRef mod,
 			   struct pipe_debug_callback *debug,
 			   unsigned processor,
 			   const char *name,
 			   bool less_optimized)
 {
-	int r = 0;
 	unsigned count = p_atomic_inc_return(&sscreen->num_compilations);
 
 	if (si_can_dump_shader(sscreen, processor)) {
 		fprintf(stderr, "radeonsi: Compiling shader %d\n", count);
 
 		if (!(sscreen->debug_flags & (DBG(NO_IR) | DBG(PREOPT_IR)))) {
 			fprintf(stderr, "%s LLVM IR:\n\n", name);
 			ac_dump_module(mod);
 			fprintf(stderr, "\n");
 		}
 	}
 
 	if (sscreen->record_llvm_ir) {
 		char *ir = LLVMPrintModuleToString(mod);
 		binary->llvm_ir_string = strdup(ir);
 		LLVMDisposeMessage(ir);
 	}
 
 	if (!si_replace_shader(count, binary)) {
-		r = si_llvm_compile(mod, binary, compiler, debug,
-				    less_optimized);
+		unsigned r = si_llvm_compile(mod, binary, compiler, debug,
+					     less_optimized);
 		if (r)
 			return r;
 	}
 
-	ac_shader_binary_read_config(binary, conf, 0, false);
+	if (!si_shader_binary_read_config(binary, conf))
+		return -1;
 
 	/* Enable 64-bit and 16-bit denormals, because there is no performance
 	 * cost.
 	 *
 	 * If denormals are enabled, all floating-point output modifiers are
 	 * ignored.
 	 *
 	 * Don't enable denormals for 32-bit floats, because:
 	 * - Floating-point output modifiers would be ignored by the hw.
 	 * - Some opcodes don't support denormals, such as v_mad_f32. We would
 	 *   have to stop using those.
 	 * - SI & CI would be very slow.
 	 */
 	conf->float_mode |= V_00B028_FP_64_DENORMS;
 
-	FREE(binary->config);
-	FREE(binary->global_symbol_offsets);
-	binary->config = NULL;
-	binary->global_symbol_offsets = NULL;
-
-	/* Some shaders can't have rodata because their binaries can be
-	 * concatenated.
-	 */
-	if (binary->rodata_size &&
-	    (processor == PIPE_SHADER_VERTEX ||
-	     processor == PIPE_SHADER_TESS_CTRL ||
-	     processor == PIPE_SHADER_TESS_EVAL ||
-	     processor == PIPE_SHADER_FRAGMENT)) {
-		fprintf(stderr, "radeonsi: The shader can't have rodata.");
-		return -EINVAL;
-	}
-
-	return r;
+	return 0;
 }
 
 static void si_llvm_build_ret(struct si_shader_context *ctx, LLVMValueRef ret)
 {
 	if (LLVMGetTypeKind(LLVMTypeOf(ret)) == LLVMVoidTypeKind)
 		LLVMBuildRetVoid(ctx->ac.builder);
 	else
 		LLVMBuildRet(ctx->ac.builder, ret);
 }
 
@@ -5567,21 +5552,25 @@ si_generate_gs_copy_shader(struct si_screen *sscreen,
 	bool ok = false;
 	if (si_compile_llvm(sscreen, &ctx.shader->binary,
 			    &ctx.shader->config, ctx.compiler,
 			    ctx.ac.module,
 			    debug, PIPE_SHADER_GEOMETRY,
 			    "GS Copy Shader", false) == 0) {
 		if (si_can_dump_shader(sscreen, PIPE_SHADER_GEOMETRY))
 			fprintf(stderr, "GS Copy Shader:\n");
 		si_shader_dump(sscreen, ctx.shader, debug,
 			       PIPE_SHADER_GEOMETRY, stderr, true);
-		ok = si_shader_binary_upload(sscreen, ctx.shader);
+
+		if (!ctx.shader->config.scratch_bytes_per_wave)
+			ok = si_shader_binary_upload(sscreen, ctx.shader, 0);
+		else
+			ok = true;
 	}
 
 	si_llvm_dispose(&ctx);
 
 	if (!ok) {
 		FREE(shader);
 		shader = NULL;
 	} else {
 		si_fix_resource_usage(sscreen, shader);
 	}
@@ -7899,30 +7888,30 @@ bool si_shader_create(struct si_screen *sscreen, struct ac_llvm_compiler *compil
 							shader->epilog->config.num_vgprs);
 		}
 		si_calculate_max_simd_waves(shader);
 	}
 
 	si_fix_resource_usage(sscreen, shader);
 	si_shader_dump(sscreen, shader, debug, sel->info.processor,
 		       stderr, true);
 
 	/* Upload. */
-	if (!si_shader_binary_upload(sscreen, shader)) {
+	if (!si_shader_binary_upload(sscreen, shader, 0)) {
 		fprintf(stderr, "LLVM failed to upload shader\n");
 		return false;
 	}
 
 	return true;
 }
 
 void si_shader_destroy(struct si_shader *shader)
 {
 	if (shader->scratch_bo)
 		si_resource_reference(&shader->scratch_bo, NULL);
 
 	si_resource_reference(&shader->bo, NULL);
 
 	if (!shader->is_binary_shared)
-		ac_shader_binary_clean(&shader->binary);
+		si_shader_binary_clean(&shader->binary);
 
 	free(shader->shader_log);
 }
diff --git a/src/gallium/drivers/radeonsi/si_shader.h b/src/gallium/drivers/radeonsi/si_shader.h
index 26cfc432899..302de427c04 100644
--- a/src/gallium/drivers/radeonsi/si_shader.h
+++ b/src/gallium/drivers/radeonsi/si_shader.h
@@ -564,20 +564,27 @@ struct si_shader_info {
 	ubyte			vs_output_param_offset[SI_MAX_VS_OUTPUTS];
 	ubyte			num_input_sgprs;
 	ubyte			num_input_vgprs;
 	signed char		face_vgpr_index;
 	signed char		ancillary_vgpr_index;
 	bool			uses_instanceid;
 	ubyte			nr_pos_exports;
 	ubyte			nr_param_exports;
 };
 
+struct si_shader_binary {
+	const char *elf_buffer;
+	uint64_t elf_size;
+
+	char *llvm_ir_string;
+};
+
 struct si_shader {
 	struct si_compiler_ctx_state	compiler_ctx_state;
 
 	struct si_shader_selector	*selector;
 	struct si_shader_selector	*previous_stage_sel; /* for refcounting */
 	struct si_shader		*next_variant;
 
 	struct si_shader_part		*prolog;
 	struct si_shader		*previous_stage; /* for GFX9 */
 	struct si_shader_part		*prolog2;
@@ -588,21 +595,21 @@ struct si_shader {
 	struct si_resource		*scratch_bo;
 	struct si_shader_key		key;
 	struct util_queue_fence		ready;
 	bool				compilation_failed;
 	bool				is_monolithic;
 	bool				is_optimized;
 	bool				is_binary_shared;
 	bool				is_gs_copy_shader;
 
 	/* The following data is all that's needed for binary shaders. */
-	struct ac_shader_binary	binary;
+	struct si_shader_binary		binary;
 	struct ac_shader_config		config;
 	struct si_shader_info		info;
 	unsigned			private_mem_vgprs;
 	unsigned			max_simd_waves;
 
 	/* Shader key + LLVM IR + disassembly + statistics.
 	 * Generated for debug contexts only.
 	 */
 	char				*shader_log;
 	size_t				shader_log_size;
@@ -647,52 +654,54 @@ struct si_shader {
 	} ctx_reg;
 
 	/*For save precompute registers value */
 	unsigned vgt_tf_param; /* VGT_TF_PARAM */
 	unsigned vgt_vertex_reuse_block_cntl; /* VGT_VERTEX_REUSE_BLOCK_CNTL */
 };
 
 struct si_shader_part {
 	struct si_shader_part *next;
 	union si_shader_part_key key;
-	struct ac_shader_binary binary;
+	struct si_shader_binary binary;
 	struct ac_shader_config config;
 };
 
 /* si_shader.c */
 struct si_shader *
 si_generate_gs_copy_shader(struct si_screen *sscreen,
 			   struct ac_llvm_compiler *compiler,
 			   struct si_shader_selector *gs_selector,
 			   struct pipe_debug_callback *debug);
 int si_compile_tgsi_shader(struct si_screen *sscreen,
 			   struct ac_llvm_compiler *compiler,
 			   struct si_shader *shader,
 			   struct pipe_debug_callback *debug);
 bool si_shader_create(struct si_screen *sscreen, struct ac_llvm_compiler *compiler,
 		     struct si_shader *shader,
 		     struct pipe_debug_callback *debug);
 void si_shader_destroy(struct si_shader *shader);
 unsigned si_shader_io_get_unique_index_patch(unsigned semantic_name, unsigned index);
 unsigned si_shader_io_get_unique_index(unsigned semantic_name, unsigned index,
 				       unsigned is_varying);
-bool si_shader_binary_upload(struct si_screen *sscreen, struct si_shader *shader);
+bool si_shader_binary_upload(struct si_screen *sscreen, struct si_shader *shader,
+			     uint64_t scratch_va);
 void si_shader_dump(struct si_screen *sscreen, const struct si_shader *shader,
 		    struct pipe_debug_callback *debug, unsigned processor,
 		    FILE *f, bool check_debug_option);
 void si_shader_dump_stats_for_shader_db(const struct si_shader *shader,
 					struct pipe_debug_callback *debug);
 void si_multiwave_lds_size_workaround(struct si_screen *sscreen,
 				      unsigned *lds_size);
-void si_shader_apply_scratch_relocs(struct si_shader *shader,
-				    uint64_t scratch_va);
 const char *si_get_shader_name(const struct si_shader *shader, unsigned processor);
+bool si_shader_binary_read_config(struct si_shader_binary *binary,
+				  struct ac_shader_config *conf);
+void si_shader_binary_clean(struct si_shader_binary *binary);
 
 /* si_shader_nir.c */
 void si_nir_scan_shader(const struct nir_shader *nir,
 			struct tgsi_shader_info *info);
 void si_nir_scan_tess_ctrl(const struct nir_shader *nir,
 			   struct tgsi_tessctrl_info *out);
 void si_lower_nir(struct si_shader_selector *sel);
 
 /* Inline helpers. */
 
diff --git a/src/gallium/drivers/radeonsi/si_shader_internal.h b/src/gallium/drivers/radeonsi/si_shader_internal.h
index 235c46ecf92..464439f5a6b 100644
--- a/src/gallium/drivers/radeonsi/si_shader_internal.h
+++ b/src/gallium/drivers/radeonsi/si_shader_internal.h
@@ -29,21 +29,20 @@
 #include "gallivm/lp_bld_flow.h"
 #include "gallivm/lp_bld_init.h"
 #include "gallivm/lp_bld_tgsi.h"
 #include "tgsi/tgsi_parse.h"
 #include "ac_shader_abi.h"
 
 #include <llvm-c/Core.h>
 #include <llvm-c/TargetMachine.h>
 
 struct pipe_debug_callback;
-struct ac_shader_binary;
 
 #define RADEON_LLVM_MAX_INPUT_SLOTS 32
 #define RADEON_LLVM_MAX_INPUTS 32 * 4
 #define RADEON_LLVM_MAX_OUTPUTS 32 * 4
 
 #define RADEON_LLVM_MAX_SYSTEM_VALUES 11
 #define RADEON_LLVM_MAX_ADDRS 16
 
 struct si_shader_context {
 	struct lp_build_tgsi_context bld_base;
@@ -211,21 +210,21 @@ si_shader_context(struct lp_build_tgsi_context *bld_base)
 	return (struct si_shader_context*)bld_base;
 }
 
 static inline struct si_shader_context *
 si_shader_context_from_abi(struct ac_shader_abi *abi)
 {
 	struct si_shader_context *ctx = NULL;
 	return container_of(abi, ctx, abi);
 }
 
-unsigned si_llvm_compile(LLVMModuleRef M, struct ac_shader_binary *binary,
+unsigned si_llvm_compile(LLVMModuleRef M, struct si_shader_binary *binary,
 			 struct ac_llvm_compiler *compiler,
 			 struct pipe_debug_callback *debug,
 			 bool less_optimized);
 
 LLVMTypeRef tgsi2llvmtype(struct lp_build_tgsi_context *bld_base,
 			  enum tgsi_opcode_type type);
 
 LLVMValueRef bitcast(struct lp_build_tgsi_context *bld_base,
 		     enum tgsi_opcode_type type, LLVMValueRef value);
 
diff --git a/src/gallium/drivers/radeonsi/si_shader_tgsi_setup.c b/src/gallium/drivers/radeonsi/si_shader_tgsi_setup.c
index 3ec919dd23b..3e27e9b0c38 100644
--- a/src/gallium/drivers/radeonsi/si_shader_tgsi_setup.c
+++ b/src/gallium/drivers/radeonsi/si_shader_tgsi_setup.c
@@ -73,48 +73,58 @@ static void si_diagnostic_handler(LLVMDiagnosticInfoRef di, void *context)
 	}
 
 	LLVMDisposeMessage(description);
 }
 
 /**
  * Compile an LLVM module to machine code.
  *
  * @returns 0 for success, 1 for failure
  */
-unsigned si_llvm_compile(LLVMModuleRef M, struct ac_shader_binary *binary,
+unsigned si_llvm_compile(LLVMModuleRef M, struct si_shader_binary *binary,
 			 struct ac_llvm_compiler *compiler,
 			 struct pipe_debug_callback *debug,
 			 bool less_optimized)
 {
 	struct ac_compiler_passes *passes =
 		less_optimized && compiler->low_opt_passes ?
 			compiler->low_opt_passes : compiler->passes;
 	struct si_llvm_diagnostics diag;
 	LLVMContextRef llvm_ctx;
 
 	diag.debug = debug;
 	diag.retval = 0;
 
 	/* Setup Diagnostic Handler*/
 	llvm_ctx = LLVMGetModuleContext(M);
 
 	LLVMContextSetDiagnosticHandler(llvm_ctx, si_diagnostic_handler, &diag);
 
 	/* Compile IR. */
-	if (!ac_compile_module_to_binary(passes, M, binary))
+	if (!ac_compile_module_to_elf(passes, M, (char **)&binary->elf_buffer,
+				      &binary->elf_size))
 		diag.retval = 1;
 
 	if (diag.retval != 0)
 		pipe_debug_message(debug, SHADER_INFO, "LLVM compile failed");
 	return diag.retval;
 }
 
+void si_shader_binary_clean(struct si_shader_binary *binary)
+{
+	free((void *)binary->elf_buffer);
+	binary->elf_buffer = NULL;
+
+	free(binary->llvm_ir_string);
+	binary->llvm_ir_string = NULL;
+}
+
 LLVMTypeRef tgsi2llvmtype(struct lp_build_tgsi_context *bld_base,
 			  enum tgsi_opcode_type type)
 {
 	struct si_shader_context *ctx = si_shader_context(bld_base);
 
 	switch (type) {
 	case TGSI_TYPE_UNSIGNED:
 	case TGSI_TYPE_SIGNED:
 		return ctx->ac.i32;
 	case TGSI_TYPE_UNSIGNED64:
diff --git a/src/gallium/drivers/radeonsi/si_state_shaders.c b/src/gallium/drivers/radeonsi/si_state_shaders.c
index b8a587b50eb..041ed1c0c62 100644
--- a/src/gallium/drivers/radeonsi/si_state_shaders.c
+++ b/src/gallium/drivers/radeonsi/si_state_shaders.c
@@ -120,83 +120,77 @@ static uint32_t *read_chunk(uint32_t *ptr, void **data, unsigned *size)
 	return read_data(ptr, *data, *size);
 }
 
 /**
  * Return the shader binary in a buffer. The first 4 bytes contain its size
  * as integer.
  */
 static void *si_get_shader_binary(struct si_shader *shader)
 {
 	/* There is always a size of data followed by the data itself. */
-	unsigned relocs_size = shader->binary.reloc_count *
-			       sizeof(shader->binary.relocs[0]);
-	unsigned disasm_size = shader->binary.disasm_string ?
-			       strlen(shader->binary.disasm_string) + 1 : 0;
 	unsigned llvm_ir_size = shader->binary.llvm_ir_string ?
 				strlen(shader->binary.llvm_ir_string) + 1 : 0;
+
+	/* Refuse to allocate overly large buffers and guard against integer
+	 * overflow. */
+	if (shader->binary.elf_size > UINT_MAX / 4 ||
+	    llvm_ir_size > UINT_MAX / 4)
+		return NULL;
+
 	unsigned size =
 		4 + /* total size */
 		4 + /* CRC32 of the data below */
 		align(sizeof(shader->config), 4) +
 		align(sizeof(shader->info), 4) +
-		4 + align(shader->binary.code_size, 4) +
-		4 + align(shader->binary.rodata_size, 4) +
-		4 + align(relocs_size, 4) +
-		4 + align(disasm_size, 4) +
+		4 + align(shader->binary.elf_size, 4) +
 		4 + align(llvm_ir_size, 4);
 	void *buffer = CALLOC(1, size);
 	uint32_t *ptr = (uint32_t*)buffer;
 
 	if (!buffer)
 		return NULL;
 
 	*ptr++ = size;
 	ptr++; /* CRC32 is calculated at the end. */
 
 	ptr = write_data(ptr, &shader->config, sizeof(shader->config));
 	ptr = write_data(ptr, &shader->info, sizeof(shader->info));
-	ptr = write_chunk(ptr, shader->binary.code, shader->binary.code_size);
-	ptr = write_chunk(ptr, shader->binary.rodata, shader->binary.rodata_size);
-	ptr = write_chunk(ptr, shader->binary.relocs, relocs_size);
-	ptr = write_chunk(ptr, shader->binary.disasm_string, disasm_size);
+	ptr = write_chunk(ptr, shader->binary.elf_buffer, shader->binary.elf_size);
 	ptr = write_chunk(ptr, shader->binary.llvm_ir_string, llvm_ir_size);
 	assert((char *)ptr - (char *)buffer == size);
 
 	/* Compute CRC32. */
 	ptr = (uint32_t*)buffer;
 	ptr++;
 	*ptr = util_hash_crc32(ptr + 1, size - 8);
 
 	return buffer;
 }
 
 static bool si_load_shader_binary(struct si_shader *shader, void *binary)
 {
 	uint32_t *ptr = (uint32_t*)binary;
 	uint32_t size = *ptr++;
 	uint32_t crc32 = *ptr++;
 	unsigned chunk_size;
+	unsigned elf_size;
 
 	if (util_hash_crc32(ptr, size - 8) != crc32) {
 		fprintf(stderr, "radeonsi: binary shader has invalid CRC32\n");
 		return false;
 	}
 
 	ptr = read_data(ptr, &shader->config, sizeof(shader->config));
 	ptr = read_data(ptr, &shader->info, sizeof(shader->info));
-	ptr = read_chunk(ptr, (void**)&shader->binary.code,
-			 &shader->binary.code_size);
-	ptr = read_chunk(ptr, (void**)&shader->binary.rodata,
-			 &shader->binary.rodata_size);
-	ptr = read_chunk(ptr, (void**)&shader->binary.relocs, &chunk_size);
-	shader->binary.reloc_count = chunk_size / sizeof(shader->binary.relocs[0]);
-	ptr = read_chunk(ptr, (void**)&shader->binary.disasm_string, &chunk_size);
+	ptr = read_chunk(ptr, (void**)&shader->binary.elf_buffer,
+			 &elf_size);
+	shader->binary.elf_size = elf_size;
 	ptr = read_chunk(ptr, (void**)&shader->binary.llvm_ir_string, &chunk_size);
 
 	return true;
 }
 
 /**
  * Insert a shader into the cache. It's assumed the shader is not in the cache.
  * Use si_shader_cache_load_shader before calling this.
  *
  * Returns false on failure, in which case the ir_binary should be freed.
@@ -3095,27 +3089,22 @@ static int si_update_scratch_buffer(struct si_context *sctx,
 
 	/* This shader is already configured to use the current
 	 * scratch buffer. */
 	if (shader->scratch_bo == sctx->scratch_buffer) {
 		si_shader_unlock(shader);
 		return 0;
 	}
 
 	assert(sctx->scratch_buffer);
 
-	if (shader->previous_stage)
-		si_shader_apply_scratch_relocs(shader->previous_stage, scratch_va);
-
-	si_shader_apply_scratch_relocs(shader, scratch_va);
-
 	/* Replace the shader bo with a new bo that has the relocs applied. */
-	if (!si_shader_binary_upload(sctx->screen, shader)) {
+	if (!si_shader_binary_upload(sctx->screen, shader, scratch_va)) {
 		si_shader_unlock(shader);
 		return -1;
 	}
 
 	/* Update the shader state to use the new shader bo. */
 	si_shader_init_pm4_state(sctx->screen, shader);
 
 	si_resource_reference(&shader->scratch_bo, sctx->scratch_buffer);
 
 	si_shader_unlock(shader);
-- 
2.20.1



More information about the mesa-dev mailing list