Home | History | Annotate | Line # | Download | only in genxml
README revision 1.1
      1  1.1  mrg This provides some background the design of the generated headers.  We
      2  1.1  mrg started out trying to generate bit fields but it evolved into the pack
      3  1.1  mrg functions because of a few limitations:
      4  1.1  mrg 
      5  1.1  mrg   1) Bit fields still generate terrible code today. Even with modern
      6  1.1  mrg      optimizing compilers you get multiple load+mask+store operations
      7  1.1  mrg      to the same dword in memory as you set individual bits. The
      8  1.1  mrg      compiler also has to generate code to mask out overflowing values
      9  1.1  mrg      (for example, if you assign 200 to a 2 bit field). Our driver
     10  1.1  mrg      never writes overflowing values so that's not needed. On the
     11  1.1  mrg      other hand, most compiler recognize that the template struct we
     12  1.1  mrg      use is a temporary variable and copy propagate the individual
     13  1.1  mrg      fields and do amazing constant folding.  You should take a look
     14  1.1  mrg      at the code that gets generated when you compile in release mode
     15  1.1  mrg      with optimizations.
     16  1.1  mrg 
     17  1.1  mrg   2) For some types we need to have overlapping bit fields. For
     18  1.1  mrg      example, some values are 64 byte aligned 32 bit offsets. The
     19  1.1  mrg      lower 5 bits of the offset are always zero, so the hw packs in a
     20  1.1  mrg      few misc bits in the lower 5 bits there. Other times a field can
     21  1.1  mrg      be either a u32 or a float. I tried to do this with overlapping
     22  1.1  mrg      anonymous unions and it became a big mess. Also, when using
     23  1.1  mrg      initializers, you can only initialize one union member so this
     24  1.1  mrg      just doesn't work with out approach.
     25  1.1  mrg 
     26  1.1  mrg      The pack functions on the other hand allows us a great deal of
     27  1.1  mrg      flexibility in how we combine things. In the case of overlapping
     28  1.1  mrg      fields (the u32 and float case), if we only set one of them in
     29  1.1  mrg      the pack function, the compiler will recognize that the other is
     30  1.1  mrg      initialized to 0 and optimize out the code to or it it.
     31  1.1  mrg 
     32  1.1  mrg   3) Bit fields (and certainly overlapping anonymous unions of bit
     33  1.1  mrg      fields) aren't generally stable across compilers in how they're
     34  1.1  mrg      laid out and aligned. Our pack functions let us control exactly
     35  1.1  mrg      how things get packed, using only simple and unambiguous bitwise
     36  1.1  mrg      shifting and or'ing that works on any compiler.
     37  1.1  mrg 
     38  1.1  mrg Once we have the pack function it allows us to hook in various
     39  1.1  mrg transformations and validation as we go from template struct to dwords
     40  1.1  mrg in memory:
     41  1.1  mrg 
     42  1.1  mrg   1) Validation: As I said above, our driver isn't supposed to write
     43  1.1  mrg      overflowing values to the fields, but we've of course had lots of
     44  1.1  mrg      cases where we make mistakes and write overflowing values. With
     45  1.1  mrg      the pack function, we can actually assert on that and catch it at
     46  1.1  mrg      runtime.  bitfields would just silently truncate.
     47  1.1  mrg 
     48  1.1  mrg   2) Type conversions: some times it's just a matter of writing a
     49  1.1  mrg      float to a u32, but we also convert from bool to bits, from
     50  1.1  mrg      floats to fixed point integers.
     51  1.1  mrg 
     52  1.1  mrg   3) Relocations: whenever we have a pointer from one buffer to
     53  1.1  mrg      another (for example a pointer from the meta data for a texture
     54  1.1  mrg      to the raw texture data), we have to tell the kernel about it so
     55  1.1  mrg      it can adjust the pointer to point to the final location. That
     56  1.1  mrg      means extra work we have to do extra work to record and annotate
     57  1.1  mrg      the dword location that holds the pointer. With bit fields, we'd
     58  1.1  mrg      have to call a function to do this, but with the pack function we
     59  1.1  mrg      generate code in the pack function to do this for us. That's a
     60  1.1  mrg      lot less error prone and less work.
     61