[Mesa-dev] [PATCH 02/11] nir: Add a pass-running infastructure

Connor Abbott cwabbott0 at gmail.com
Wed Oct 28 20:48:49 PDT 2015


On Wed, Oct 28, 2015 at 8:51 PM, Jason Ekstrand <jason at jlekstrand.net> wrote:
> On Wed, Oct 28, 2015 at 5:41 PM, Connor Abbott <cwabbott0 at gmail.com> wrote:
>> On Wed, Oct 28, 2015 at 8:00 PM, Jason Ekstrand <jason at jlekstrand.net> wrote:
>>> On Wed, Oct 28, 2015 at 4:26 PM, Connor Abbott <cwabbott0 at gmail.com> wrote:
>>>> While it works for now, I'm not so sure about how we're conflating the
>>>> definition of a pass and its dynamic instantiation. Eventually we'll
>>>> want to have passes refer to each other ("please run pass B after pass
>>>> A to clean up its mess", etc.), and in that case we need to be able to
>>>> have to the pass itself add a pointer to another pass inside its pass
>>>> struct, and then look up the dynamic pass associated with it after
>>>> we're done loading all the passes (if it exists). That would be easier
>>>> if we removed the closure pointer from nir_pass and made it a purely
>>>> static thing, and instead added a new struct or made the closure
>>>> argument be passed around separately. Otherwise we'd have to match the
>>>> contents of the struct, which doesn't seem like the right thing to do.
>>>
>>> Yeah, I thought about that.  Unfortunately, I haven't come up with a
>>> good way to make it work easily.  One option would be to have another
>>> struct with a pointer to the pass and the data but that makes building
>>> a pass list kind of messy.  I also considered not having a closure at
>>> all and just putting everything in nir_compiler_options but that's not
>>> a good idea either as it will pollute the nir_compiler_options struct
>>> and doesn't allow for custom passes with options.
>>>
>>> Here's another option which I hadn't previously considered:  Pass in a
>>> list of pass-data pairs something like
>>>
>>> struct {
>>>    nir_pass *pass;
>>>    void *data;
>>> }
>>>
>>> where you only have to pass data in for the passes that need it.  That
>>> way the list of passes and the extra arguments provided are completely
>>> orthogonal.  It would mean either a hash lookup or a linear walk over
>>> the pass data for every pass, but you should only have 3 or 4 things
>>> in there and we can add a field to nir_pass to indicate whether or not
>>> a pass takes arguments.  The over-all overhead should be minimal.  It
>>> does require, however, that the nir_pass pointers are unique which
>>> shouldn't be a problem.
>>
>> Well, the other option to consider would be to not pass in an array at
>> all and instead have functions to construct a pass manager and then
>> have a function to add a pass (with associated void  * pointer) to it
>> like in LLVM. You could even do C-style subclassing instead of passing
>> a pointer, if you wanted to. The advantage here is that adding passes
>> is more flexible, since it's not in one giant array: for example, you
>> could have a function like nir_add_common_passes() that adds DCE, copy
>> prop, CSE, and other stuff that every driver should have, and then
>> have the drivers call it instead of duplicating them 3 times (and
>> having to add every pass 3 times, and sometimes forgetting to!).
>>
>> As to resolving static pass instances to dynamic ones: I think this
>> can be done at pass creation time, or at least before the loop runs.
>> You keep an internal array of pass datastructures that are augmented
>> with references to the instantion of the pass that you got handed, if
>> it exists, and initialize it after you've added all the passes but
>> before running them. Of course, we don't have to do this until later
>> though.
>
> Yeah, a pass manager seems a bit heavy-handed for now.  The big thing
> is not to paint ourselves into a corner.  Once we have a pass
> infrastructure in place, people can play with it a bit in different
> drivers and we can see what we like.  At the very least, we should
>
>  1) Pull the data pointer out of nir_pass
>  2) Make nir_shader_optimize take an array of pointers.
>
> I'm not sure what to do about the data pointer.  We could pull it out
> entirely for the moment but it will have to go back in somewhere.  Not
> very far into the future, I'm going to want to port the rest of the
> passes and then we'll need a real solution.

Ok, fair enough. I think adding a separate struct with the data
pointer like you said sounds like the way to go for now, although I
can see how it could be somewhat painful until/unless we have a
separate pass builder object.

>
>>>
>>>> On Wed, Oct 28, 2015 at 5:32 PM, Jason Ekstrand <jason at jlekstrand.net> wrote:
>>>>> ---
>>>>>  src/glsl/nir/nir.h      | 19 +++++++++++++++
>>>>>  src/glsl/nir/nir_pass.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++-
>>>>>  2 files changed, 82 insertions(+), 1 deletion(-)
>>>>>
>>>>> diff --git a/src/glsl/nir/nir.h b/src/glsl/nir/nir.h
>>>>> index e3777f9..069c7c1 100644
>>>>> --- a/src/glsl/nir/nir.h
>>>>> +++ b/src/glsl/nir/nir.h
>>>>> @@ -1582,6 +1582,25 @@ typedef struct nir_shader {
>>>>>        foreach_list_typed(nir_function_overload, overload, node, \
>>>>>                           &(func)->overload_list)
>>>>>
>>>>> +typedef struct nir_pass {
>>>>> +   bool (*shader_pass_func)(nir_shader *shader, void *data);
>>>>> +   bool (*impl_pass_func)(nir_function_impl *impl, void *data);
>>>>> +   nir_metadata metadata_preserved;
>>>>> +   void *data;
>>>>> +} nir_pass;
>>>>> +
>>>>> +static inline nir_pass
>>>>> +nir_pass_with_data(nir_pass pass, void *data)
>>>>> +{
>>>>> +   pass.data = data;
>>>>> +   return pass;
>>>>> +}
>>>>> +
>>>>> +bool nir_shader_run_pass(nir_shader *shader, const nir_pass *pass);
>>>>> +bool nir_function_impl_run_pass(nir_function_impl *impl, const nir_pass *pass);
>>>>> +bool nir_shader_optimize(nir_shader *shader,
>>>>> +                         const nir_pass *passes, unsigned num_passes);
>>>>> +
>>>>>  nir_shader *nir_shader_create(void *mem_ctx,
>>>>>                                gl_shader_stage stage,
>>>>>                                const nir_shader_compiler_options *options);
>>>>> diff --git a/src/glsl/nir/nir_pass.c b/src/glsl/nir/nir_pass.c
>>>>> index a03e124..059d016 100644
>>>>> --- a/src/glsl/nir/nir_pass.c
>>>>> +++ b/src/glsl/nir/nir_pass.c
>>>>> @@ -27,7 +27,7 @@
>>>>>  #include "nir.h"
>>>>>
>>>>>  /*
>>>>> - * Handles management of the metadata.
>>>>> + * Handles management of NIR passes and metadata.
>>>>>   */
>>>>>
>>>>>  void
>>>>> @@ -52,3 +52,65 @@ nir_metadata_preserve(nir_function_impl *impl, nir_metadata preserved)
>>>>>  {
>>>>>     impl->valid_metadata &= preserved;
>>>>>  }
>>>>> +
>>>>> +static bool
>>>>> +_function_impl_run_pass(nir_function_impl *impl, const nir_pass *pass)
>>>>> +{
>>>>> +   bool progress = pass->impl_pass_func(impl, pass->data);
>>>>> +   if (progress)
>>>>> +      nir_metadata_preserve(impl, pass->metadata_preserved);
>>>>> +
>>>>> +   return progress;
>>>>> +}
>>>>> +
>>>>> +bool
>>>>> +nir_function_impl_run_pass(nir_function_impl *impl, const nir_pass *pass)
>>>>> +{
>>>>> +   bool progress = _function_impl_run_pass(impl, pass);
>>>>> +
>>>>> +   /* TODO: Add a way to validate a single function_impl */
>>>>> +   nir_validate_shader(impl->overload->function->shader);
>>>>> +
>>>>> +   return progress;
>>>>> +}
>>>>> +
>>>>> +bool
>>>>> +nir_shader_run_pass(nir_shader *shader, const nir_pass *pass)
>>>>> +{
>>>>> +   bool progress;
>>>>> +   if (pass->shader_pass_func) {
>>>>> +      progress = pass->shader_pass_func(shader, pass->data);
>>>>> +
>>>>> +      if (progress) {
>>>>> +         nir_foreach_overload(shader, overload) {
>>>>> +            if (overload->impl)
>>>>> +               nir_metadata_preserve(overload->impl, pass->metadata_preserved);
>>>>> +         }
>>>>> +      }
>>>>> +   } else {
>>>>> +      progress = false;
>>>>> +      nir_foreach_overload(shader, overload) {
>>>>> +         if (overload->impl)
>>>>> +            progress |= _function_impl_run_pass(overload->impl, pass);
>>>>> +      }
>>>>> +   }
>>>>> +
>>>>> +   return progress;
>>>>> +}
>>>>> +
>>>>> +bool
>>>>> +nir_shader_optimize(nir_shader *shader,
>>>>> +                    const nir_pass *passes, unsigned num_passes)
>>>>> +{
>>>>> +   bool progress, total_progress = false;
>>>>> +
>>>>> +   do {
>>>>> +      progress = false;
>>>>> +      for (unsigned p = 0; p < num_passes; p++)
>>>>> +         progress |= nir_shader_run_pass(shader, &passes[p]);
>>>>> +
>>>>> +      total_progress |= progress;
>>>>> +   } while (progress);
>>>>> +
>>>>> +   return total_progress;
>>>>> +}
>>>>> --
>>>>> 2.5.0.400.gff86faf
>>>>>
>>>>> _______________________________________________
>>>>> mesa-dev mailing list
>>>>> mesa-dev at lists.freedesktop.org
>>>>> http://lists.freedesktop.org/mailman/listinfo/mesa-dev


More information about the mesa-dev mailing list