[Mesa-dev] [PATCH v6 4/6] mesa/st: glsl_to_tgsi: add register rename mapping evaluator

Nicolai Hähnle nhaehnle at gmail.com
Sun Jul 16 18:32:04 UTC 2017


On 04.07.2017 16:18, Gert Wollny wrote:
> The remapping evaluator first sorts the temporary registers ascending
> based on their first life time instruction, and then uses a binary search
> to find merge canidates.
> For the initial sorting it uses std::sort because qsort is quite slow in
> comparison. By removing the define USE_STL_SORT in
>    src/mesa/state_tracker/st_glsl_to_tgsi_temprename.cpp
> one can enable the alternative code path that uses qsort.
> 
> Registers that are not used in the shader are not considered for renaming,
> registeres that are only read (undefined behaviour) may be renamed

*registers


> abitrarily.
> ---
>   .../state_tracker/st_glsl_to_tgsi_temprename.cpp   | 117 +++++++++++++++++++++
>   .../state_tracker/st_glsl_to_tgsi_temprename.h     |  12 +++
>   2 files changed, 129 insertions(+)
> 
> diff --git a/src/mesa/state_tracker/st_glsl_to_tgsi_temprename.cpp b/src/mesa/state_tracker/st_glsl_to_tgsi_temprename.cpp
> index f85a6fa7c9..3269f6ae6a 100644
> --- a/src/mesa/state_tracker/st_glsl_to_tgsi_temprename.cpp
> +++ b/src/mesa/state_tracker/st_glsl_to_tgsi_temprename.cpp
> @@ -841,6 +841,123 @@ lifetime temp_comp_access::get_required_lifetime()
>      return make_lifetime(first_dominant_write, last_read);
>   }
>   
> +/* helper class for sorting and searching the registers based
> + * on life times. */
> +struct access_record {
> +   int begin;
> +   int end;
> +   int reg;
> +   bool erase;
> +
> +   bool operator < (const access_record& rhs) const {
> +      return begin < rhs.begin;
> +   }
> +};
> +
> +/* Find the next register between [start, end) that has a life time starting
> + * at or after bound by using a binary search.
> + * start points at the beginning of the search range,
> + * end points at the element past the end of the search range, and
> + * the array comprising [start, end) must be sorted in ascending order.
> + */
> +static access_record*
> +find_next_rename(access_record* start, access_record* end, int bound)
> +{
> +   int delta = (end - start);
> +
> +   while (delta > 0)  {
> +      int half = delta >> 1;
> +      access_record* middle = start + half;
> +
> +      if (bound <= middle->begin) {
> +         delta = half;
> +      } else {
> +         start = middle;
> +         ++start;
> +         delta -= half + 1;
> +      }
> +   }
> +
> +   return start;
> +}
> +
> +#ifndef USE_STL_SORT
> +static int access_record_compare (const void *a, const void *b) {
> +   const access_record *aa = static_cast<const access_record*>(a);
> +   const access_record *bb = static_cast<const access_record*>(b);
> +   return aa->begin < bb->begin ? -1 : (aa->begin > bb->begin ? 1 : 0);
> +}
> +#endif

Add an extra line of whitespace here.


> +/* This functions evaluates the register merges by using an buínary
> + * search to find suitable merge candidates. */
> +void get_temp_registers_remapping(void *mem_ctx, int ntemps,
> +                                  const struct lifetime* lifetimes,
> +                                  struct rename_reg_pair *result)
> +{
> +

... and remove this one.


> +   /* The first record is empty and only used for simpler indexing,
> +    * hence, for the mapping evaluation we only need ntemps-1 values
> +    */

Is that really true? I though TMP[0] could be used by real code.


> +   access_record *reg_access = ralloc_array(mem_ctx, access_record, ntemps - 1);
> +
> +   for (int i = 1; i < ntemps; ++i) {
> +      reg_access[i-1].begin =  lifetimes[i].begin;
> +      reg_access[i-1].end = lifetimes[i].end;
> +      reg_access[i-1].reg = i;
> +      reg_access[i-1].erase = false;

Spaces around operators everywhere.


> +   }
> +
> +#ifdef USE_STL_SORT
> +   std::sort(reg_access, reg_access + ntemps - 1);
> +#else
> +   std::qsort(reg_access, ntemps - 1, sizeof(access_record), access_record_compare);
> +#endif
> +
> +   access_record *reg_access_end = reg_access + ntemps - 1;
> +   access_record *trgt = find_next_rename(reg_access, reg_access_end, 0);

What's the point of this? If you want to skip registers with entirely 
undefined lifetimes, why not just leave them out of the reg_access 
array? It's admittedly a minor point.


> +
> +   access_record *first_erase = reg_access_end;
> +   access_record *search_start = trgt + 1;
> +
> +   while (trgt != reg_access_end) {
> +      access_record *src = find_next_rename(search_start, reg_access_end,
> +                                            trgt->end);
> +      if (src !=  reg_access_end) {

Remove extra space after !=

Apart from this, the patch looks good.

Cheers,
Nicolai


> +         result[src->reg].new_reg = trgt->reg;
> +         result[src->reg].valid = true;
> +         trgt->end = src->end;
> +
> +         /* Since we only search forward, don't remove the renamed
> +          * register just now, only mark it. */
> +         src->erase = true;
> +
> +         if (first_erase == reg_access_end)
> +            first_erase = src;
> +
> +         search_start = src + 1;
> +      } else {
> +         /* Moving to the next target register it is time to remove
> +          * the already merged registers from the search range */
> +         if (first_erase != reg_access_end) {
> +            access_record *outp = first_erase;
> +            access_record *inp = first_erase + 1;
> +
> +            while (inp != reg_access_end) {
> +               if (!inp->erase)
> +                  *outp++ = *inp;
> +               ++inp;
> +            }
> +
> +            reg_access_end = outp;
> +            first_erase = reg_access_end;
> +         }
> +         ++trgt;
> +         search_start = trgt + 1;
> +      }
> +   }
> +   ralloc_free(reg_access);
> +}
> +
>   /* Code below used for debugging */
>   #ifndef NDEBUG
>   static const char swizzle_txt[5] = "xyzw";
> diff --git a/src/mesa/state_tracker/st_glsl_to_tgsi_temprename.h b/src/mesa/state_tracker/st_glsl_to_tgsi_temprename.h
> index 44998cca97..6fa8e2c9f6 100644
> --- a/src/mesa/state_tracker/st_glsl_to_tgsi_temprename.h
> +++ b/src/mesa/state_tracker/st_glsl_to_tgsi_temprename.h
> @@ -51,5 +51,17 @@ struct lifetime {
>   void
>   get_temp_registers_required_lifetimes(void *mem_ctx, exec_list *instructions,
>                                         int ntemps, struct lifetime *lifetimes);
> +/** Estimate the merge remapping of the registers.
> + * @param[in] mem_ctx a memory context that can be used with the ralloc_* functions
> + * @param[in] ntemps number of temporaries reserved for this shader
> + * @param[in] lifetimes required life time for each temporary register.
> + * @param[in,out] result memory location to store the register remapping table.
> + *  On input the parameter must point to allocated memory that can hold the
> + *  renaming information for ntemps registers, on output the mapping is stored.
> + *  Note that TEMP[0] is not considered for register renaming.
> + */
> +void get_temp_registers_remapping(void *mem_ctx, int ntemps,
> +                                  const struct lifetime* lifetimes,
> +                                  struct rename_reg_pair *result);
>   
>   #endif
> \ No newline at end of file
> 


-- 
Lerne, wie die Welt wirklich ist,
Aber vergiss niemals, wie sie sein sollte.


More information about the mesa-dev mailing list