assert((int)stage >= 0 && stage < ARRAY_SIZE(stage_sizes));
return stage_sizes[stage];
}
+
+void
+brw_write_shader_relocs(const struct gen_device_info *devinfo,
+ void *program,
+ const struct brw_stage_prog_data *prog_data,
+ struct brw_shader_reloc_value *values,
+ unsigned num_values)
+{
+ for (unsigned i = 0; i < prog_data->num_relocs; i++) {
+ assert(prog_data->relocs[i].offset % 8 == 0);
+ brw_inst *inst = (brw_inst *)(program + prog_data->relocs[i].offset);
+ for (unsigned j = 0; j < num_values; j++) {
+ if (prog_data->relocs[i].id == values[j].id) {
+ brw_update_reloc_imm(devinfo, inst, values[j].value);
+ break;
+ }
+ }
+ }
+}
#define BRW_PARAM_BUILTIN_CLIP_PLANE_COMP(param) \
(((param) - BRW_PARAM_BUILTIN_CLIP_PLANE_0_X) & 0x3)
+/** Represents a code relocation
+ *
+ * Relocatable constants are immediates in the code which we want to be able
+ * to replace post-compile with the actual value.
+ */
+struct brw_shader_reloc {
+ /** The 32-bit ID of the relocatable constant */
+ uint32_t id;
+
+ /** The offset in the shader to the relocatable instruction
+ *
+ * This is the offset to the instruction rather than the immediate value
+ * itself. This allows us to do some sanity checking while we relocate.
+ */
+ uint32_t offset;
+};
+
+/** A value to write to a relocation */
+struct brw_shader_reloc_value {
+ /** The 32-bit ID of the relocatable constant */
+ uint32_t id;
+
+ /** The value with which to replace the relocated immediate */
+ uint32_t value;
+};
+
struct brw_stage_prog_data {
struct {
/** size of our binding table. */
unsigned const_data_size;
unsigned const_data_offset;
+ unsigned num_relocs;
+ const struct brw_shader_reloc *relocs;
+
/** Does this program pull from any UBO or other constant buffers? */
bool has_ubo_pull;
const struct brw_cs_prog_data *cs_prog_data,
unsigned group_size);
+void
+brw_write_shader_relocs(const struct gen_device_info *devinfo,
+ void *program,
+ const struct brw_stage_prog_data *prog_data,
+ struct brw_shader_reloc_value *values,
+ unsigned num_values);
+
/**
* Calculate the RightExecutionMask field used in GPGPU_WALKER.
*/
return (const unsigned *)p->store;
}
+const brw_shader_reloc *
+brw_get_shader_relocs(struct brw_codegen *p, unsigned *num_relocs)
+{
+ *num_relocs = p->num_relocs;
+ return p->relocs;
+}
+
bool brw_try_override_assembly(struct brw_codegen *p, int start_offset,
const char *identifier)
{
int *if_depth_in_loop;
int loop_stack_depth;
int loop_stack_array_size;
+
+ struct brw_shader_reloc *relocs;
+ int num_relocs;
+ int reloc_array_size;
};
struct brw_label {
void brw_disassemble(const struct gen_device_info *devinfo,
const void *assembly, int start, int end,
const struct brw_label *root_label, FILE *out);
+const struct brw_shader_reloc *brw_get_shader_relocs(struct brw_codegen *p,
+ unsigned *num_relocs);
const unsigned *brw_get_program( struct brw_codegen *p, unsigned *sz );
bool brw_try_override_assembly(struct brw_codegen *p, int start_offset,
brw_float_controls_mode(struct brw_codegen *p,
unsigned mode, unsigned mask);
+void
+brw_update_reloc_imm(const struct gen_device_info *devinfo,
+ brw_inst *inst,
+ uint32_t value);
+
+void
+brw_MOV_reloc_imm(struct brw_codegen *p,
+ struct brw_reg dst,
+ enum brw_reg_type src_type,
+ uint32_t id);
+
/***********************************************************************
* brw_eu_util.c:
*/
}
p->nr_insn = p->next_insn_offset / sizeof(brw_inst);
+ for (int i = 0; i < p->num_relocs; i++) {
+ if (p->relocs[i].offset < (uint32_t)start_offset)
+ continue;
+
+ assert(p->relocs[i].offset % 16 == 0);
+ unsigned idx = (p->relocs[i].offset - start_offset) / 16;
+ p->relocs[i].offset -= compacted_counts[idx] * 8;
+ }
+
/* Update the instruction offsets for each group. */
if (disasm) {
int offset = 0;
if (p->devinfo->gen >= 12)
brw_SYNC(p, TGL_SYNC_NOP);
}
+
+void
+brw_update_reloc_imm(const struct gen_device_info *devinfo,
+ brw_inst *inst,
+ uint32_t value)
+{
+ /* Sanity check that the instruction is a MOV of an immediate */
+ assert(brw_inst_opcode(devinfo, inst) == BRW_OPCODE_MOV);
+ assert(brw_inst_src0_reg_file(devinfo, inst) == BRW_IMMEDIATE_VALUE);
+
+ /* If it was compacted, we can't safely rewrite */
+ assert(brw_inst_cmpt_control(devinfo, inst) == 0);
+
+ brw_inst_set_imm_ud(devinfo, inst, value);
+}
+
+/* A default value for constants that will be patched at run-time.
+ * We pick an arbitrary value that prevents instruction compaction.
+ */
+#define DEFAULT_PATCH_IMM 0x4a7cc037
+
+void
+brw_MOV_reloc_imm(struct brw_codegen *p,
+ struct brw_reg dst,
+ enum brw_reg_type src_type,
+ uint32_t id)
+{
+ assert(type_sz(src_type) == 4);
+ assert(type_sz(dst.type) == 4);
+
+ if (p->num_relocs + 1 > p->reloc_array_size) {
+ p->reloc_array_size = MAX2(16, p->reloc_array_size * 2);
+ p->relocs = reralloc(p->mem_ctx, p->relocs,
+ struct brw_shader_reloc, p->reloc_array_size);
+ }
+
+ p->relocs[p->num_relocs++] = (struct brw_shader_reloc) {
+ .id = id,
+ .offset = p->next_insn_offset,
+ };
+
+ brw_MOV(p, dst, retype(brw_imm_ud(DEFAULT_PATCH_IMM), src_type));
+}