With exciting new variable locations from instruction referencing comes exciting new ways for locations to be broken. I've run into a sample where LLVM reduces the size of an enumeration value from 32 bits to a single byte, inserting the relevant DW_OP_convert's. Unfortunately, when the single byte is spilt to the stack we describe it's location correctly, but the fact that it's only one byte is omitted. Consumers faced with a stack location and DW_OP_deref quite naturally load 32 bits from the stack instead of 8 bits, which then corrupts the variable value displayed.
The location can be correctly described with DW_OP_deref_size. This patch seeks out the size of the value and the size of the variable, and uses DW_OP_deref_size if they don't match.
While that's fairly simple, doing this stumbles into the awkward problem of whether locations should be:
- A location expression with an implicit deref,
- A location expression with a DW_OP_stack_value,
and we're forced to commit to one of them at this point, because it affects where the DW_OP_deref{,_size} is placed. There are then several different inputs to location-production that need to be handled. The result is a four-case if/else block, which is unfortunate, but is a gnarly problem that should be designed away at a later date.
Other test changes aside from the one added: one test needs the variable size corrected to avoid spurious changes. Another test with a FIXME is fixed (live-debug-values-restore.mir), the problem was that we have to change the expression produced for a stack slot depending on whether there's already a non-empty DIExpression. For an empty expression, adding "DW_OP_uconst, 8" and becoming a location expression with implicit deref is sufficient. But if there's something else in the expression, we have to explicitly add DW_OP_deref so that the other expression operators can operate on the loaded value. Ugly, but here we are.
nit: ValueSizeInBits instead?