<div dir="ltr">On 19 December 2013 13:30, Francisco Jerez <span dir="ltr"><<a href="mailto:currojerez@riseup.net" target="_blank">currojerez@riseup.net</a>></span> wrote:<br><div class="gmail_extra"><div class="gmail_quote">
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="HOEnZb"><div class="h5">Paul Berry <<a href="mailto:stereotype441@gmail.com">stereotype441@gmail.com</a>> writes:<br>

<br>
> On 2 December 2013 11:31, Francisco Jerez <<a href="mailto:currojerez@riseup.net">currojerez@riseup.net</a>> wrote:<br>
><br>
>> diff --git a/src/mesa/drivers/dri/i965/brw_shader.h<br>
>> b/src/mesa/drivers/dri/i965/brw_shader.h<br>
>> index ff5af93..f284389 100644<br>
>> --- a/src/mesa/drivers/dri/i965/brw_shader.h<br>
>> +++ b/src/mesa/drivers/dri/i965/brw_shader.h<br>
>> @@ -23,6 +23,7 @@<br>
>><br>
>>  #include <stdint.h><br>
>>  #include "brw_defines.h"<br>
>> +#include "brw_reg.h"<br>
>>  #include "glsl/ir.h"<br>
>><br>
>>  #pragma once<br>
>> @@ -39,6 +40,45 @@ enum register_file {<br>
>><br>
>>  #ifdef __cplusplus<br>
>><br>
>> +class backend_reg {<br>
>> +public:<br>
>> +   backend_reg();<br>
>> +   backend_reg(struct brw_reg reg);<br>
>> +<br>
>> +   bool is_zero() const;<br>
>> +   bool is_one() const;<br>
>> +   bool is_null() const;<br>
>> +<br>
>> +   /** Register file: GRF, MRF, IMM. */<br>
>> +   enum register_file file;<br>
>> +<br>
>> +   /**<br>
>> +    * Register number.  For MRF, it's the hardware register.  For<br>
>> +    * GRF, it's a virtual register number until register allocation<br>
>> +    */<br>
>> +   int reg;<br>
>> +<br>
>> +   /**<br>
>> +    * Offset from the start of the contiguous register block.<br>
>> +    *<br>
>> +    * For pre-register-allocation GRFs, this is in units of a float per<br>
>> pixel<br>
>> +    * (1 hardware register for SIMD8 mode, or 2 registers for SIMD16<br>
>> mode).<br>
>><br>
><br>
> Since this code is now shared with the vec4 back-end, can we update this<br>
> comment to say "1 hardware register for SIMD8 or SIMD4x2 mode..."?<br>
><br>
><br>
>> +    * For uniforms, this is in units of 1 float.<br>
>> +    */<br>
>> +   int reg_offset;<br>
>> +<br>
>> +   /** Register type.  BRW_REGISTER_TYPE_* */<br>
>> +   int type;<br>
>> +   struct brw_reg fixed_hw_reg;<br>
>> +<br>
>> +   /** Value for file == BRW_IMMMEDIATE_FILE */<br>
>> +   union {<br>
>> +      int32_t i;<br>
>> +      uint32_t u;<br>
>> +      float f;<br>
>> +   } imm;<br>
>> +};<br>
>> +<br>
>>  class backend_instruction : public exec_node {<br>
>>  public:<br>
>>     bool is_tex();<br>
>> diff --git a/src/mesa/drivers/dri/i965/brw_vec4.h<br>
>> b/src/mesa/drivers/dri/i965/brw_vec4.h<br>
>> index 3b3f35b..a718333 100644<br>
>> --- a/src/mesa/drivers/dri/i965/brw_vec4.h<br>
>> +++ b/src/mesa/drivers/dri/i965/brw_vec4.h<br>
>> @@ -89,28 +89,7 @@ class dst_reg;<br>
>>  unsigned<br>
>>  swizzle_for_size(int size);<br>
>><br>
>> -class reg<br>
>> -{<br>
>> -public:<br>
>> -   /** Register file: GRF, MRF, IMM. */<br>
>> -   enum register_file file;<br>
>> -   /** virtual register number.  0 = fixed hw reg */<br>
>> -   int reg;<br>
>> -   /** Offset within the virtual register. */<br>
>> -   int reg_offset;<br>
>> -   /** Register type.  BRW_REGISTER_TYPE_* */<br>
>> -   int type;<br>
>> -   struct brw_reg fixed_hw_reg;<br>
>> -<br>
>> -   /** Value for file == BRW_IMMMEDIATE_FILE */<br>
>> -   union {<br>
>> -      int32_t i;<br>
>> -      uint32_t u;<br>
>> -      float f;<br>
>> -   } imm;<br>
>> -};<br>
>> -<br>
>> -class src_reg : public reg<br>
>> +class src_reg : public backend_reg<br>
>>  {<br>
>>  public:<br>
>>     DECLARE_RALLOC_CXX_OPERATORS(src_reg)<br>
>> @@ -123,10 +102,9 @@ public:<br>
>>     src_reg(uint32_t u);<br>
>>     src_reg(int32_t i);<br>
>>     src_reg(struct brw_reg reg);<br>
>> +   src_reg(const backend_reg &reg);<br>
>><br>
><br>
> I'm concerned about this constructor (and the corresponding constructors in<br>
> the dst_reg and fs_reg classes) contributing to object slicing problems.<br>
> Consider this code:<br>
><br>
>     src_reg r1;<br>
>     r1.swizzle = BRW_SWIZZLE_XXXX;<br>
>     backend_reg r2(r1);<br>
>     src_reg r3(r2);<br>
>     assert(r3.swizzle == BRW_SWIZZLE_XXXX); /* fails! */<br>
><br>
> The reason for the failure is that src_reg::swizzle doesn't appear in the<br>
> backend_reg base class.  So when r1 is copied to r2, the value of swizzle<br>
> is lost.  That by itself wouldn't be a problem, except that when we later<br>
> try to reconstruct a src_reg from r2, swizzle winds up being initialized to<br>
> the default value.<br>
><br>
> Of course we would never write code like the above example directly, but<br>
> since your shared code for implementing loads/stores (in future patches)<br>
> uses backend_reg for all of its register representations, it seems likely<br>
> that a src_reg will get converted to a backend_reg and then back to a<br>
> src_reg at some point during compilation.  So I suspect that when compiling<br>
> GLSL source code like the following:<br>
><br>
>     uniform image2D img;<br>
>     ivec2 coord;<br>
>     vec4 v;<br>
>     imageStore(img, coord, v.yzwx);<br>
><br>
> The swizzle would fail to take effect.<br>
><br>
> Have you run tests to see if this is in fact the case?<br>
><br>
<br>
</div></div>I haven't, but I'm aware of this problem.  It's one of the things I wish<br>
I had finished before I left.  I had a few solutions in mind, all of<br>
them likely to be time-consuming and not especially compelling:<br>
<br>
 - Rename what I called backend_reg to e.g. base_reg, make it an<br>
   abstract base class or use some other technique to prevent its<br>
   construction.  Now backend_reg would be implemented as a sort of<br>
   type-erased wrapper for the other kinds of regs.  This wouldn't be<br>
   too hard because the only thing we need backend_regs for is to pass<br>
   values around, the actual uses of those regs know about the real<br>
   register types.<br>
<br>
 - Prevent construction of backend_reg as before, but pass them around<br>
   as pointers instead of by value.  This would be simple but kind of<br>
   annoying and inconsistent with the current value semantics of the<br>
   other register classes.<br>
<br>
 - Make backend_reg a member variable rather than a base class to<br>
   prevent unsafe up-casting.  We could have helper functions to convert<br>
   a fs/vec4 reg into a backend reg that check if the original register<br>
   region parameters are the identity mapping and, if they are not, copy<br>
   the value over to some temporary storage.  Assignments would be<br>
   handled by the visitor itself rather than the surface lowering code.<br>
<br>
 - Use static rather than dynamic polymorphism in the shared code, which<br>
   would be parameterized by the correct register type.  There is really<br>
   no reason for the shared code to be a (polymorphic) class, other than<br>
   to avoid templates.<br>
<br>
I think right now I'm leaning towards possibility 1, but I'll give the<br>
matter another thought and try to get one of these solutions working<br>
when I find the time.  I can't promise when that will happen though.<br>
<br>
Let me know if you come up with anything else.<br>
<br>
Thanks.<br></blockquote><div><br></div><div>I played around a little bit yesterday with the last option (using static rather than dynamic polymorphism), and I like what I came up with, but it involves templates so it would be a hard sell for a lot of folks.  I'm hoping that I can have an in-person conversation with some of the Intel developers about this so that we can hash it out in person without things getting too flamey.  Unfortunately, several people have already started their holiday vacations, so that conversation probably won't happen until the new year.<br>
</div></div></div></div>