This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[RFC] DW_OP_piece vs. DW_OP_bit_piece on a Register


The following is mainly targeted at readers with a strong DWARF
background.  Anybody else may read for interest/amusement or safely
ignore.

After analyzing some test case failures in GCC and GDB I realized that
there are various problems with the handling of DWARF pieces
(particularly from registers) in the current implementations of GCC and
GDB.  I'm working on a fix for the GDB part, but first I'd like to check
whether I'm heading into the right direction -- or what the right
direction is supposed to be.  The article below outlines these issues
and the suggested solution options.

Any kind of feedback is greatly appreciated!

-- 
Andreas

-- >8 --
	    _______________________________________________

	     DW_OP_PIECE VS. DW_OP_BIT_PIECE ON A REGISTER

			     Andreas Arnez
	    _______________________________________________


			    <2016-01-14 Thu>


Table of Contents
_________________

1 Overview
2 Example Scenarios
.. 2.1 z/Architecture Floating-Point- and Vector Registers
.. 2.2 SPU Preferred Slot
3 Current State And Issues
.. 3.1 DW_OP_bit_piece on a Register
..... 3.1.1 DWARF Definition of DW_OP_bit_piece
..... 3.1.2 Current GCC Usage of DW_OP_bit_piece
..... 3.1.3 Current GDB Handling of DW_OP_bit_piece
.. 3.2 DW_OP_piece on a Register
..... 3.2.1 DWARF Definition of DW_OP_piece
..... 3.2.2 Current GCC Usage of DW_OP_piece
..... 3.2.3 Current GDB Handling of DW_OP_piece
4 Options
.. 4.1 Literal Interpretation
..... 4.1.1 Discussion
.. 4.2 Loose Interpretation
..... 4.2.1 Discussion
.. 4.3 Same Scheme for Bit- and Byte Pieces
..... 4.3.1 Discussion
5 Padding
.. 5.1 Stack Values
.. 5.2 Registers
.. 5.3 Padding: Options
..... 5.3.1 No padding support
..... 5.3.2 Padding support for integer stack values
..... 5.3.3 Padding support for stack values and registers
6 Summary of Open Questions





1 Overview
==========

  While trying to fix various problems with the handling of DWARF pieces
  in GDB, it turned out that there are some inconsistencies between the
  DWARF standard on one hand and the handling in GCC and GDB on the
  other hand.

  Questions that came up include: Which of a register's bits are
  designated by the DW_OP_piece and DW_OP_bit_piece operations?  What
  does the DWARF standard say?  How does GCC currently use these
  operations?  What do we actually want?


2 Example Scenarios
===================

  Scenarios involving DWARF pieces are probably more interesting on
  big-endian platforms.  Consider the following examples.


2.1 z/Architecture Floating-Point- and Vector Registers
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  While the general (integer) registers on z/Architecture have a fairly
  strong natural right-alignment, this is not true for floating point
  registers and vector registers.  Instead, the following holds:
  - Values are usually left-aligned in floating-point registers.
  - Each 64-bit floating-point register is embedded left-aligned in a
    128-bit vector register, and both have the same DWARF register
    number.

  ,----
  | :<--      FP Register        -->:
  | :                               :
  | :    float                      :
  | +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
  | |///|///|///|///|   |   |   |   |   |   |   |   |   |   |   |   |
  | +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
  | |///|///|///|///|///|///|///|///|   |   |   |   |   |   |   |   |
  | +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
  |             double
  `----

  Now consider a pieced object with one of its pieces residing in a
  floating-point register.  If represented as a piece of the respective
  vector register, which offset should be used for DW_OP_bit_piece?  Can
  DW_OP_piece be used?

  Or consider multiple variables which are scheduled into a single
  vector register, due to straight-line vectorization.  How should the
  locations of these variables be represented in DWARF?


2.2 SPU Preferred Slot
~~~~~~~~~~~~~~~~~~~~~~

  SPU registers have a "preferred slot" for storing scalar values of a
  particular size:
  ,----
  |              char
  | +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
  | | 0 |   |   |///|   |   |   |   | 8 |   |   |   |   |   |   | 15|
  | +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
  | 
  |           short
  | +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
  | |   |   |///|///|   |   |   |   |   |   |   |   |   |   |   |   |
  | +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
  | 
  |        int
  | +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
  | |///|///|///|///|   |   |   |   |   |   |   |   |   |   |   |   |
  | +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
  | 
  |             long long
  | +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
  | |///|///|///|///|///|///|///|///|   |   |   |   |   |   |   |   |
  | +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
  `----
  The DWARF location of such a scalar value would typically be described
  with DW_OP_reg<n> or DW_OP_regx, without a piece operation.  It is
  then up to the debugger to determine the placement of the value within
  the register.  In GDB this is implemented with the gdbarch method
  `value_from_register'.

  Now, how do the DWARF piece operations relate to these preferred
  slots?


3 Current State And Issues
==========================

  GCC and GDB currently have various problems and inconsistencies in
  their usage and handling of DW_OP_bit_piece and DW_OP_piece.
  Additionally, this area may be a bit under-specified in the DWARF
  standard.  The following sections give an overview of the current
  state.


3.1 DW_OP_bit_piece on a Register
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  DW_OP_bit_piece has been added to DWARF as a more general way of
  describing pieces than DW_OP_piece.  However, after its introduction
  in DWARF-3, it was supported neither by GCC nor GDB for quite some
  time, and its support is still incomplete and widely broken.


3.1.1 DWARF Definition of DW_OP_bit_piece
-----------------------------------------

  The standard says: "If the location is a register, the offset is from
  the least significant bit end of the register."


* 3.1.1.1 Which is a register's "least significant bit"?

  Some clarification may be needed here.  For instance, consider a
  register that can naturally hold various-sized integers, but with
  their least significant bits at different positions, such as an SPU
  register.  Or consider a vector register that can not naturally hold a
  single full-size integer.

  Maybe, assuming that each register has some defined byte order, the
  least significant bit refers to the appropriate bit in the register's
  first or last byte, for little- or big-endian targets, respectively.
  In other words, bit pieces with offset 0 would be taken from the left
  on little-endian targets and from the right on big-endian targets.

  Note that this definition precludes "register growth" beyond the right
  end in future versions of a big-endian architecture, such as with the
  floating point registers on z, when they were extended to vector
  registers.  On the other hand, extending an integer register from 32
  to 64 bit (or more) would work nicely.

  Also note that this definition implies opposite bit ordering on
  typical big-endian targets for register- versus memory locations.  For
  the latter the DWARF standard requests "using the bit numbering and
  direction conventions that are appropriate to the current language on
  the target system".  And on big-endian targets this typically means
  MSB0 bit order.


* 3.1.1.2 What is the rationale for this definition?

  It is not obvious why DW_OP_bit_piece is defined differently for
  registers as for memory locations.  One possible reason may be to
  allow appropriate register growth, but that goal is not met either, as
  illustrated by the example in 2.1.  Is there some other rationale?


3.1.2 Current GCC Usage of DW_OP_bit_piece
------------------------------------------

  GCC seems to generate DW_OP_bit_piece only for variables that have
  been optimized by SRA, in `dw_sra_loc_expr'.  For register locations
  the piece offset is then always zero.

  However, if the offset is zero and the size is a multiple of 8,
  DW_OP_bit_piece is not actually used, but DW_OP_piece is emitted
  instead, obviously under the assumption that this is a shorter way of
  describing the same piece.  Such "simplification" logic can be found
  in LLVM as well.

  GCC does not seem to emit DW_OP_bit_piece for multiple variables
  residing in a single vector register.  Instead, no DWARF location is
  emitted at all for these variables.


3.1.3 Current GDB Handling of DW_OP_bit_piece
---------------------------------------------

  GDB interprets the offset and size of DW_OP_bit_piece for registers as
  suggested above: Bit pieces are taken from the right on big-endian
  targets, and from the left on little-endian targets.

  However, the implementation in GDB has various issues that often lead
  to incorrect results when trying to access bit pieces.  For instance,
  when the bit size is not a multiple of 8, GDB usually corrupts the
  result.  Also, non-zero bit offsets are unsupported and silently
  replaced by zero.  These issues are mostly independent from the
  questions raised here, and work is under way to fix them.


3.2 DW_OP_piece on a Register
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  As opposed to DW_OP_bit_piece, the older DW_OP_piece operation
  describes byte-aligned pieces only and does not allow specifying an
  offset.  Issues with this operation in GCC and GDB are mostly
  restricted to "corner cases" like naturally left-aligned registers on
  big-endian platforms.


3.2.1 DWARF Definition of DW_OP_piece
-------------------------------------

  The standard says: "If the piece is located in a register, but does
  not occupy the entire register, the placement of the piece within that
  register is defined by the ABI."

  This seems to imply the following:
  1. The placement rule of DW_OP_piece is not necessarily related to the
     placement rule of DW_OP_bit_piece.  In particular, it would be
     invalid to assume that DW_OP_piece is equivalent to DW_OP_bit_piece
     with offset 0.  (But note that this is exactly what GCC and GDB
     currently assume.)
  2. The placement can depend on the register as well as on size of the
     piece.  For instance, DW_OP_piece could be defined in accordance
     with the SPU preferred slot.


* 3.2.1.1 What exactly may be defined by the ABI?

  The standard is not explicit about the flexibility granted to the
  ABI-specifics here.  In particular:
  - Do the pieces have to be contiguous?
  - Assuming that the placement can depend on the size, must a piece at
    least include all smaller pieces?
  - Does a single-byte piece have to be at either end of the register?


3.2.2 Current GCC Usage of DW_OP_piece
--------------------------------------

  GCC emits DW_OP_piece for a value that spans more than one register,
  or for a virtual concatenation such as a complex value, etc.

  One example is a `long double' value on z that has been scheduled into
  a floating-point register pair.  GCC represents this as a composition
  of two DW_OP_piece operations of size 8, each referring to the *left*
  end of the respective vector register.

  GCC also emits DW_OP_piece for a register when an SRA-optimized field
  with a multiple-of-8 bit size has been scheduled into it.  This seems
  to be under the assumption that DW_OP_piece is equivalent to
  DW_OP_bit_piece with offset 0.  One case where this is wrong is for an
  `__int128' bit field residing in a vector register on z.  Then the
  DW_OP_piece emitted by GCC refers to the *right* end of the vector
  register.

  Another case where this would be wrong is when, say, a 56-bit
  SRA-optimized bit field had been spilled into a floating-point
  register.  Then the actual bits reside at a non-zero offset from
  *either* end of the vector register.


3.2.3 Current GDB Handling of DW_OP_piece
-----------------------------------------

  GDB internally translates DW_OP_piece into DW_OP_bit_piece with offset
  0 and the appropriate bit size.  Then it takes the bitwise piece from
  the left end on little-endian targets and from the right on big-endian
  targets.  Otherwise no ABI-specific logic is applied.

  This is wrong for the floating-point-registers on z.  For instance,
  when a `complex float' value is pieced together from two
  floating-point registers, the pieces ought to be taken from the left
  end, but GDB takes them from the right end, typically yielding zero.


4 Options
=========

  There are several different ways of fixing the issues described above.
  However, the choice depends on how the DWARF standard is interpreted.
  Here are some suggestions.


4.1 Literal Interpretation
~~~~~~~~~~~~~~~~~~~~~~~~~~

  DW_OP_bit_piece: Start from the least significant bit of the first/last
                   register's byte on little-/big-endian targets,
                   respectively.
  DW_OP_piece: Apply an ABI-specific placement rule which may depend on
               the register and the piece length.

  Also, whenever possible, define the ABI-specific placement rule for
  DW_OP_piece such that DW_OP_regx is equivalent to DW_OP_regx followed
  by `DW_OP_piece(len)', where `len' is the size of the object's data
  type.  In the case of z this means to take pieces from the left end
  for FPRs/vector registers, and from the right end for general
  (integer) registers.  And for SPU registers it means to arrange the
  pieces according to the "preferred slots".

  But DW_OP_bit_piece, on the other hand, then uses offsets >= 64 to
  designate any piece of an FPR on z.  This is true even on older
  systems without vector registers, because the DWARF register numbers
  are the same -- offset zero is invalid there!


4.1.1 Discussion
----------------

  Pros:
  - This interpretation seems as close as possible to the current
    standard's wording.
  - DW_OP_piece can be used for cases like the SPU preferred slots.

  Cons:
  - The fact that FPRs on z start with a non-zero offset is rather odd
    and could even be considered a violation of the standard.  An
    alternative might be to change the DWARF output of future compilers,
    such as to assign new DWARF register numbers to vector registers.
    However, that would render existing compilers' DWARF locations
    invalid when vector registers are involved.
  - Registers can not grow at the end of their "least significant bit".
    The growth from 64-bit FPRs to 128-bit vector registers on z can be
    accommodated with some drawbacks as explained above, but in the
    future such cases would likely be handled by adding new DWARF
    register numbers.

  Resulting To-Dos:
  - In the DWARF standard, clear up the meaning of the least significant
    bit and highlight the difference between the placement rules of
    DW_OP_piece and DW_OP_bit_piece.  Add that DW_OP_piece shall be
    equivalent to *some* DW_OP_bit_piece operation, but not necessarily
    with offset 0.
  - In GCC, drop the translation from DW_OP_bit_piece to DW_OP_piece, or
    do it more carefully and involve ABI-specific logic.
  - Enable GCC to emit DW_OP_bit_piece with a non-zero offset, for
    instance in cases where an SRA-optimized bit field has been spilled
    into an FPR on z.
  - Equip GDB with ABI-specific logic for translating DW_OP_piece to the
    appropriate bit piece.


4.2 Loose Interpretation
~~~~~~~~~~~~~~~~~~~~~~~~

  DW_OP_bit_piece: Allow the ABI to define a per-register bit numbering
                   scheme.
  DW_OP_piece: Apply an ABI-specific placement rule.

  This is similar to the previous option but may avoid the issue with
  invalid offset 0 within FPRs on z, e.g., by starting from the
  register's *first* byte in this case.

  Bit numbering schemes for DW_OP_bit_piece may be:

   Architecture   Alignment  Bit order 
  -------------------------------------
   little-endian  left       LSB0      
   little-endian  right      MSB0      
   big-endian     right      LSB0      
   big-endian     left       MSB0      

  For instance, the right-aligned little-endian scheme starts with the
  most significant bit of the register's last byte.  The FPRs and vector
  registers on z might use the left-aligned big-endian scheme, which
  starts with the most significant bit of the first byte.


4.2.1 Discussion
----------------

  Pros:
  - Each register can grow in an ABI-defined direction.  This also
    avoids the issue with non-zero offsets for FPRs on z.
  - As with the "literal interpretation", DW_OP_piece can be used for
    the SPU preferred slots.

  Cons:
  - Not quite in line with the current standard's wording, unless
    assuming a fairly loose interpretation of "least significant bit".
  - Requires two different ABI-specific mappings for DWARF pieces
    instead of just one.  This affects DWARF producers and consumers
    alike.

  Resulting To-Dos:
  - Replace the DWARF standard's wording around the "least significant
    bit".  Enumerate the supported bit numbering schemes instead, and
    state that the ABI shall assign one of them to each register.
    Highlight the difference to DW_OP_piece.
  - Fix GCC's translation from DW_OP_bit_piece to DW_OP_piece.
  - In GCC, add an ABI-specific mapping from SRA-optimized bit fields to
    DWARF bit pieces.
  - Equip GDB with ABI-specific logic for translating DW_OP_piece to the
    appropriate bit piece, as well as for assigning a bit numbering
    scheme to each register.


4.3 Same Scheme for Bit- and Byte Pieces
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  DW_OP_bit_piece: Allow the ABI to define a per-register bit numbering
                   scheme.
  DW_OP_piece: Same as the appropriately sized DW_OP_bit_piece at offset
               0.

  This definition is similar to the loose interpretation, but maintains
  the assumption built into GCC, GDB, LLVM, and possibly other
  DWARF-aware programs, that DW_OP_piece is just a short-hand notation
  for DW_OP_bit_piece with offset 0.

  However, this definition does not support the use of DW_OP_piece for
  designating the SPU preferred slots.  DW_OP_bit_piece must then be
  used instead.


4.3.1 Discussion
----------------

  Pros:
  - Each register can grow in an ABI-defined direction.
  - Maintains the assumption built into (all?) DWARF-aware software,
    that DW_OP_piece translates to a DW_OP_bit_piece with offset 0.

  Cons:
  - Does not comply with the current standard's wording.
  - DW_OP_piece can not be used for the SPU preferred slots.

  Resulting To-Dos:
  - Replace the DWARF standard's wording around the "least significant
    bit" by an enumeration of supported bit numbering schemes and the
    statement that the ABI shall assign one of them to each register.
    Also define DW_OP_piece as DW_OP_bit_piece with offset 0.
  - In GCC, add an ABI-specific mapping from SRA-optimized bit fields to
    DWARF bit pieces.


5 Padding
=========

  A related question is how to deal with a DWARF piece operation that
  reaches fully or partially outside its underlying object.  This is
  currently not specified by the DWARF standard.  It should probably be
  stated that such a DWARF expression is invalid because pieces must be
  fully contained in their underlying objects.  Or otherwise it should
  be explained where the extra bits are inserted, and how their values
  are defined.


5.1 Stack Values
~~~~~~~~~~~~~~~~

  For example, consider the following location description:

  ,----
  | DW_OP_lit0 DW_OP_stack_value DW_OP_piece 936
  `----

  It *could* be argued that this is an efficient way of describing the
  value of a 936-byte structure containing all zeroes.

  Then, consequently, in this example...

  ,----
  | DW_OP_const1s -1 DW_OP_stack_value DW_OP_piece 80
  `----

  ...sign extension would be performed.

  One reason to support the validity of such location descriptions is
  that operations like DW_OP_lit<n> do not specify an object size, but
  their resulting value could be viewed as having *infinite* size
  instead.  Of course, a different point of view is that the literal is
  sign-extended to the special DWARF5 address type, thereby defining the
  object size.

  The examples above have an obvious natural alignment: The padding is
  inserted beyond the end of the most significant bit, such that pieces
  are right-aligned on big-endian targets and left-aligned on
  little-endian targets.  It is less obvious how this concept extends to
  non-integer stack values.


5.2 Registers
~~~~~~~~~~~~~

  For a location description like this there may or may not be a natural
  alignment and padding:

  ,----
  | DW_OP_reg5 DW_OP_bit_piece 1000 23
  `----

  To define the alignment, one option may be to follow the bit numbering
  scheme used for DW_OP_bit_piece on that particular register.  Padding
  bits would then be inserted beyond the highest-numbered bit.

  The value of the padding bits should probably always be set to zero,
  because it is generally unknown whether the register currently holds a
  signed or unsigned value.


5.3 Padding: Options
~~~~~~~~~~~~~~~~~~~~

  Depending on the DWARF standard interpretation, one of the following
  options could be pursued.


5.3.1 No padding support
------------------------

  With this option, the DWARF standard might leave this area
  unspecified, or perhaps explicitly state that pieces shall be fully
  contained in their underlying objects.

  DWARF consumers should then emit errors upon encountering invalid
  pieces.  GDB, for instance, does not currently emit such errors.


5.3.2 Padding support for integer stack values
----------------------------------------------

  With this option, pieces must still be contained in their underlying
  objects, except for integer stack values.  Those are appropriately
  sign-extended.  In particular, this might be an efficient way of
  describing large areas initialized with zero.


5.3.3 Padding support for stack values and registers
----------------------------------------------------

  With this option, pieces reaching outside their underlying objects
  would generally be padded, for stack values as well as for registers.

  Padding and alignment for non-integer stack values and for registers
  would have to be defined.  It seems that, unless a very simple (yet
  meaningful) scheme is found, it is probably not worth pursuing this.


6 Summary of Open Questions
===========================

  1. Out of the standard interpretations discussed under "options"
     (section 4) above, which do we want to settle on?  Or is the
     "preferred" interpretation missing from that list?
  2. Should pieces fully or partially outside their underlying objects
     be considered valid or invalid?  If valid, how should they be
     aligned and padded?  In any case, what is the suggested treatment
     by a DWARF consumer?


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]