intel/eu: Add a mechanism for emitting relocatable constant MOVs
authorJason Ekstrand <jason@jlekstrand.net>
Sat, 8 Aug 2020 17:55:29 +0000 (12:55 -0500)
committerMarge Bot <eric+marge@anholt.net>
Wed, 2 Sep 2020 19:48:44 +0000 (19:48 +0000)
Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/6244>

src/intel/compiler/brw_compiler.c
src/intel/compiler/brw_compiler.h
src/intel/compiler/brw_eu.cpp
src/intel/compiler/brw_eu.h
src/intel/compiler/brw_eu_compact.c
src/intel/compiler/brw_eu_emit.c

index a04cf9650113219377b45d95dd1fd180b2c14f59..a5b90e9b3c9e00b4db2c4f8eb7844bb923b5f3a6 100644 (file)
@@ -267,3 +267,22 @@ brw_prog_key_size(gl_shader_stage stage)
    assert((int)stage >= 0 && stage < ARRAY_SIZE(stage_sizes));
    return stage_sizes[stage];
 }
    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;
+         }
+      }
+   }
+}
index 679a78723fe9e5577a2642d405373823e306b207..01fd0d034e55bd72fccf95cca4e9e2154eb177a3 100644 (file)
@@ -642,6 +642,32 @@ enum brw_param_builtin {
 #define BRW_PARAM_BUILTIN_CLIP_PLANE_COMP(param) \
    (((param) - BRW_PARAM_BUILTIN_CLIP_PLANE_0_X) & 0x3)
 
 #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. */
 struct brw_stage_prog_data {
    struct {
       /** size of our binding table. */
@@ -688,6 +714,9 @@ struct brw_stage_prog_data {
    unsigned const_data_size;
    unsigned const_data_offset;
 
    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;
 
    /** Does this program pull from any UBO or other constant buffers? */
    bool has_ubo_pull;
 
@@ -1535,6 +1564,13 @@ brw_cs_simd_size_for_group_size(const struct gen_device_info *devinfo,
                                 const struct brw_cs_prog_data *cs_prog_data,
                                 unsigned group_size);
 
                                 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.
  */
 /**
  * Calculate the RightExecutionMask field used in GPGPU_WALKER.
  */
index 0027b0a396552caf9bb027574826d41c495d76ac..4bd52df5085651761b1a63f56ec48783f8debc78 100644 (file)
@@ -363,6 +363,13 @@ const unsigned *brw_get_program( struct brw_codegen *p,
    return (const unsigned *)p->store;
 }
 
    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)
 {
 bool brw_try_override_assembly(struct brw_codegen *p, int start_offset,
                                const char *identifier)
 {
index 7622cff8f6a2424a679c2147863f8daf2ad7370d..88cf9d1d67461a5d7bbe1ae1ac4d96534d09c7dc 100644 (file)
@@ -136,6 +136,10 @@ struct brw_codegen {
    int *if_depth_in_loop;
    int loop_stack_depth;
    int loop_stack_array_size;
    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 {
 };
 
 struct brw_label {
@@ -184,6 +188,8 @@ void brw_disassemble_with_labels(const struct gen_device_info *devinfo,
 void brw_disassemble(const struct gen_device_info *devinfo,
                      const void *assembly, int start, int end,
                      const struct brw_label *root_label, FILE *out);
 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,
 const unsigned *brw_get_program( struct brw_codegen *p, unsigned *sz );
 
 bool brw_try_override_assembly(struct brw_codegen *p, int start_offset,
@@ -1238,6 +1244,17 @@ void
 brw_float_controls_mode(struct brw_codegen *p,
                         unsigned mode, unsigned mask);
 
 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:
  */
 /***********************************************************************
  * brw_eu_util.c:
  */
index f880d790b850b1c372344748e8b7a6c9a66d1eaa..d7c352236429bc0dc70093952c6ae01675b45ff8 100644 (file)
@@ -2446,6 +2446,15 @@ brw_compact_instructions(struct brw_codegen *p, int start_offset,
    }
    p->nr_insn = p->next_insn_offset / sizeof(brw_inst);
 
    }
    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;
    /* Update the instruction offsets for each group. */
    if (disasm) {
       int offset = 0;
index e6c6dcb1607aaad1f418a668eacef3ac2ffe0893..c9c180b1fcc9bdad7c623cf50fd51b0085e0ab33 100644 (file)
@@ -3641,3 +3641,46 @@ brw_float_controls_mode(struct brw_codegen *p,
    if (p->devinfo->gen >= 12)
       brw_SYNC(p, TGL_SYNC_NOP);
 }
    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));
+}