<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<style type="text/css" style="display:none;"> P {margin-top:0;margin-bottom:0;} </style>
</head>
<body dir="ltr">
> That sounds to me to be the same concept that I am calling r-value vs. l-value. Do you agree, or is there some subtlety that I am missing?
<div><br>
</div>
<div>I've been assuming that the l-value vs r-value distinction is analogous to C++: an l-value can be written to by the debugger, an r-value cannot. A memory location and a register location are both l-values, while implicit locations (stack value/implicit
 pointer) are r-values. Directness on the other hand, I've been using to mean "the variable's value is equal to the value computed by the DIExpression". Applied to a DWARF expression this description would only refer to a stack value. LLVM's DIExpressions are
 different however, because we don't have DW_OP_reg or DW_OP_breg: we simply refer to the register and use context to determine which it should be. The best example of this is from this example[0], expanded on here with the location type:</div>
<div style="font-family: Calibri, Arial, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0)">
<br>
</div>
<div><span style="font-family: Consolas, Courier, monospace">$noreg, (plus_uconst, 8),                -> DW_OP_breg7 RSP+8)                    Memory    l-value  Indirect</span></div>
<div><span style="font-family: Consolas, Courier, monospace">     0, (plus_uconst, 8),                -> DW_OP_breg7 RSP+8)                    Memory    l-value  Indirect</span></div>
<div><span style="font-family: Consolas, Courier, monospace">$noreg, (plus_uconst, 8, stackval),      -> DW_OP_breg7 RSP+8, stackval           Stack     r-value  Direct</span></div>
<div><span style="font-family: Consolas, Courier, monospace">     0, (plus_uconst, 8, stackval),      -> DW_OP_breg7 RSP+8, stackval           Stack     r-value  Direct</span></div>
<div><span style="font-family: Consolas, Courier, monospace">$noreg, (plus_uconst, 8, deref),         -> DW_OP_breg7 RSP+8                     Memory    l-value  Indirect</span></div>
<div><span style="font-family: Consolas, Courier, monospace">     0, (plus_uconst, 8, deref),         -> DW_OP_breg7 RSP+8, deref              Memory    l-value  Indirect</span></div>
<div><span style="font-family: Consolas, Courier, monospace">$noreg, (plus_uconst, 8, deref, stackval)-> DW_OP_breg7 RSP+8, deref, stackval    Stack     r-value  Direct</span></div>
<div><span style="font-family: Consolas, Courier, monospace">     0, (plus_uconst, 8, deref, stackval)-> DW_OP_breg7 RSP+8, deref, stackval    Stack     r-value  Direct</span></div>
<div><span style="font-family: Consolas, Courier, monospace">$noreg, (),                              -> DW_OP_reg7 RSP                        Register  l-value  Direct</span></div>
<div><span style="font-family: Consolas, Courier, monospace">     0, (),                              -> DW_OP_breg7 RSP+0                     Memory    l-value  Indirect</span></div>
<div><span style="font-family: Consolas, Courier, monospace">$noreg, (deref),                         -> DW_OP_breg7 RSP+0                     Memory    l-value  Indirect</span></div>
<div><span style="font-family: Consolas, Courier, monospace">     0, (deref),                         -> DW_OP_breg7 RSP+0, DW_OP_deref        Memory    l-value  Indirect</span></div>
<div><br>
</div>
<div>The point of using DW_OP_LLVM_direct is that it supplants the current directness flag, without the redundancy or unintuitive behaviour that the flag does. I believe the only reason that the indirectness flag is necessary right now is to allow register
 locations to be emitted, by delineating the register location "$rsp, $noreg, ()" -> DW_OP_reg7 RSP" from the memory location "$rsp, 0, () -> DW_OP_breg7 RSP+0". Outside of this case the existing representation is sufficient for all other locations, and ideally
 the indirectness flag would have no effect (although unfortunately it does). The justification for DW_OP_LLVM_direct rests on the idea that we will generally choose to produce "DW_OP_reg7 RSP" instead of "DW_OP_breg7 RSP, DW_OP_stack_value". It doesn't prevent
 us from using DW_OP_stack_value instead if we have an exception, but I don't believe there are any. Using DW_OP_LLVM_direct instead of directness and stackval for the table above, we get this:</div>
<br>
<div><span style="font-family: Consolas, Courier, monospace">(plus_uconst, 8),                     -> DW_OP_breg7 RSP+8                     Memory    l-value  Indirect</span></div>
<div><span style="font-family: Consolas, Courier, monospace">(plus_uconst, 8, LLVM_direct),        -> DW_OP_breg7 RSP+8, stackval           Stack     r-value  Direct</span></div>
<div><span style="font-family: Consolas, Courier, monospace">(plus_uconst, 8, deref),              -> DW_OP_breg7 RSP+8, deref              Memory    l-value  Indirect</span></div>
<div><span style="font-family: Consolas, Courier, monospace">(plus_uconst, 8, deref, LLVM_direct), -> DW_OP_breg7 RSP+8, deref, stackval    Stack     r-value  Direct</span></div>
<div><span style="font-family: Consolas, Courier, monospace">(),                                   -> DW_OP_breg7 RSP+0                     Memory    l-value  Inirect</span></div>
<div><span style="font-family: Consolas, Courier, monospace">(LLVM_direct),                        -> DW_OP_reg7 RSP                        Register  l-value  Direct</span></div>
<div><span style="font-family: Consolas, Courier, monospace">(deref),                              -> DW_OP_breg7 RSP+0, deref              Memory    l-value  Indirect</span></div>
<div><span style="font-family: Consolas, Courier, monospace">(deref, LLVM_direct),                 -> DW_OP_breg7 RSP+0, deref, stackval    Stack     r-value  Direct</span></div>
<div><br>
</div>
<div>Two of the examples in this table should be excluded from actual use: the two rows that end with "deref, LLVM_direct" shouldn't be produced within LLVM, because we can cancel the two operators out to give a memory location rather than producing a "deref,
 stackval" expression. This can be done in LLVM itself through the DIExpression interface, so that we don't hold DIExpressions in an incorrect intermediate state. I'm currently operating under the belief that if a dbg.value can be an l-value, it always should
 be; if not, then we can use DW_OP_stack_value instead in all cases where we require a given dbg.value to be an r-value.</div>
<div><br>
</div>
<div>To give an example of why having this could be more useful than just applying stack value, consider a hypothetical "DIExpression optimizer" pass applied to the following code:</div>
<br>
<div><span style="font-family: Consolas, Courier, monospace">    // `int a` is live...</span></div>
<div><span style="font-family: Consolas, Courier, monospace"><span>    </span>int b = a + 5;</span></div>
<div><span style="font-family: Consolas, Courier, monospace"><span>    </span>int c = b - 5;</span></div>
<div><br>
</div>
<div>If both b and c are optimized out and salvaged, then we end up with the following dbg.values:</div>
<div><br>
</div>
<div><span style="font-family: Consolas, Courier, monospace">    @llvm.dbg.value(i32 %a, !"b", !DIExpression(DW_OP_plus_uconst, 5, DW_OP_LLVM_direct))</span></div>
<div><span style="font-family: Consolas, Courier, monospace">    @llvm.dbg.value(i32 %a, !"c", !DIExpression(DW_OP_plus_uconst, 5, DW_OP_constu, 5, DW_OP_minus, DW_OP_LLVM_direct))</span></div>
<div><span style="font-family: Consolas, Courier, monospace">    ; DIExpressions optimized...</span></div>
<div><span style="font-family: Consolas, Courier, monospace">    @llvm.dbg.value(i32 %a, !"b", !DIExpression(DW_OP_plus_uconst, 5, DW_OP_LLVM_direct))</span></div>
<div><span style="font-family: Consolas, Courier, monospace">    @llvm.dbg.value(i32 %a, !"c", !DIExpression(DW_OP_LLVM_direct))</span></div>
<div><br>
</div>
<div><span style="font-family: "Segoe UI", "Helvetica Neue", sans-serif">In this admittedly strange case, we start with b and c as l-values (before they are optimized out), they then become r-values due to optimization, and finally c is a valid l-value again.
 If we instead applied </span><span style="font-family: "Segoe UI", "Helvetica Neue", sans-serif">DW_OP_stack_value
</span><span style="font-family: "Segoe UI", "Helvetica Neue", sans-serif">when we salvage, then c would not be recovered as an l-value. If we had
</span><span style="font-family: "Segoe UI", "Helvetica Neue", sans-serif">DW_OP_implicit_ptr
</span><span style="font-family: "Segoe UI", "Helvetica Neue", sans-serif">instead of DW_OP_LLVM_direct, then the result would be an r-value either way; likewise if we were referencing a memory location, the result would be an l-value regardless of how we modi</span>fied
 it.</div>
<div><br>
</div>
<div>I suspect there may be disagreements over whether c should share an l-value location with a, since this means that a user could write to either c or a, and that doing so would assign to both of them. My personal belief is that even if it seems confusing,
 we shouldn't arbitrarily restrict write-access to variables on criteria that will not always be clear to a debug user; whether or not to apply such a restriction should be left to the debugger, rather than being baked into the information we produce for it.
 Personal opinions aside, the other reason I'm taking this approach right now is that it matches LLVM's existing behaviour. If we have the source code:</div>
<br>
<div><span style="font-family: Consolas, Courier, monospace">    </span><span style="font-family: Consolas, Courier, monospace">int a = ...</span></div>
<div><span style="font-family: Consolas, Courier, monospace">    </span><span style="font-family: Consolas, Courier, monospace">int b = a;</span></div>
<div><br>
</div>
<div>We will produce the IR:</div>
<br>
<div><span style="font-family: Consolas, Courier, monospace"><span>    </span>call void @llvm.dbg.value(metadata i32 %a, metadata !13, metadata !DIExpression()), !dbg !15</span></div>
<div><span style="font-family: Consolas, Courier, monospace"><span>    </span>call void @llvm.dbg.value(metadata i32 %a, metadata !14, metadata !DIExpression()), !dbg !15</span></div>
<br>
<div>This IR will in turn produce register locations for both variables at the same location. Based on that, I believe that the current expected behaviour is that if two source variables map to the same actual location then they should share a DWARF location.</div>
<div><br>
</div>
<div>> Here is an example of why I think that an optimization pass must have the ability to downgrade an l-value to an r-value:</div>
<div>> ...</div>
<div>> The optimization eliminated the store of constant 0 to %mem and replaced all loads of %mem in the subsequent block with a constant "i32 0". This means that we need mark the first dbg.value (that would otherwise look like an l-value) as an r-value, because
 writing a new value to %mem there would not affect the code that is now hardcoded to use a constant 0 value for x.</div>
<div><br>
</div>
<div>The behaviour seen by the user in this case is:</div>
<div><br>
</div>
<div><span style="font-family: Consolas, Courier, monospace">; BEFORE</span></div>
<div><span style="font-family: Consolas, Courier, monospace">call %llvm.dbg.declare(%mem, !DILocalVariable("x"))</span></div>
<div><span style="font-family: Consolas, Courier, monospace">store i32* %mem, i32 %foo</span></div>
<div><span style="font-family: Consolas, Courier, monospace">; "x" is set to %foo, and can be written to</span></div>
<div><span style="font-family: Consolas, Courier, monospace">...</span></div>
<div><span style="font-family: Consolas, Courier, monospace">store i32* %mem, i32 0</span></div>
<div><span style="font-family: Consolas, Courier, monospace">; "x" is set to 0, and can be written to</span></div>
<div><span style="font-family: Consolas, Courier, monospace">...</span></div>
<div><span style="font-family: Consolas, Courier, monospace">store i32* %mem, i32 %foo</span></div>
<div><span style="font-family: Consolas, Courier, monospace">; "x" is set to %foo, and can be written to</span></div>
<div><span style="font-family: Consolas, Courier, monospace">...</span></div>
<div><br>
</div>
<div><span style="font-family: Consolas, Courier, monospace">; AFTER</span></div>
<div><span style="font-family: Consolas, Courier, monospace">call %llvm.dbg.value(%mem, !DILocalVariable("x"), !DIExpression(DW_OP_deref))</span></div>
<div><span style="font-family: Consolas, Courier, monospace">store i32* %mem, i32 %foo</span></div>
<div><span style="font-family: Consolas, Courier, monospace">; "x" is set to %foo, and can be written to</span></div>
<div><span style="font-family: Consolas, Courier, monospace">...</span></div>
<div><span style="font-family: Consolas, Courier, monospace">call %llvm.dbg.value(%mem, !DILocalVariable("x"), !DIExpression(DW_OP_constu 0, DW_OP_stack_value))</span></div>
<div><span style="font-family: Consolas, Courier, monospace">; "x" is set to %foo, and is read-only</span></div>
<div><span style="font-family: Consolas, Courier, monospace">...</span></div>
<div><span style="font-family: Consolas, Courier, monospace">call %llvm.dbg.value(%mem, !DILocalVariable("x"), !DIExpression(DW_OP_deref))</span></div>
<div><span style="font-family: Consolas, Courier, monospace">; "x" is set to its value prior to 0, and can be written to</span></div>
<div><span style="font-family: Consolas, Courier, monospace">...</span></div>
<div><br>
</div>
<div>I don't think there's any issue with a variable being an r-value at some points in its live range and an l-value at others; in this case I think it's correct that the first dbg.value should be an l-value. Any write to
<span style="font-family: Consolas, Courier, monospace">x</span> will not affect the code after the eliminated store, but even without optimizations x would be set to 0 (overriding any debugger assignment) at that point anyway. I do agree that the code produced
 may be slightly confusing to a user; this code likely maps to something along the lines of:</div>
<div><br>
</div>
<div><span style="font-family: Consolas, Courier, monospace"><span>    </span>int x = foo;</span></div>
<div><span style="font-family: Consolas, Courier, monospace"><span>    </span>...</span></div>
<div><span style="font-family: Consolas, Courier, monospace"><span>    </span>x = 0;</span></div>
<div><span style="font-family: Consolas, Courier, monospace"><span>    </span>...</span></div>
<div><span style="font-family: Consolas, Courier, monospace"><span>    </span>x = foo;</span></div>
<div><br>
</div>
<div><span style="font-family: "Segoe UI", "Helvetica Neue", sans-serif">I</span><span style="font-family: "Segoe UI", "Helvetica Neue", sans-serif">f the user breaks just after the first "</span><span style="font-family: "Segoe UI", "Helvetica Neue", sans-serif">x
 = foo</span><span style="font-family: "Segoe UI", "Helvetica Neue", sans-serif">" and assigns `</span><span style="font-family: "Segoe UI", "Helvetica Neue", sans-serif">x = 5</span><span style="font-family: "Segoe UI", "Helvetica Neue", sans-serif">` in the
 debugger, they will see the correct result for all subsequent uses of x until the next assignment to x. When they step over "x = 0", x has the value 0 (as expected) and it becomes read-only. Finally after stepping over the next "x = foo" they will see that
 `x == 5`, which might not make a lot of sense when the user is expecting it to be assigned a different value. Even so, this information is a correct representation of the program state.</span></div>
<div><br>
</div>
<div><span style="font-family: "Segoe UI", "Helvetica Neue", sans-serif">The alternative of making the first dbg.value an r-value is restrictive - if the initial assignment to x is at the top of a large function that the user is debugging, and the other two
 assignments occur at the very end, it would likely be frustrating to the user that they have no write-access to x throughout the function. Because of this I don't believe that it would be right to make the first dbg.value an r-value; I think again that choosing
 to apply these restrictions should be left to the debugger.</span></div>
<div><br>
</div>
[0] <a href="https://bugs.llvm.org/show_bug.cgi?id=41675#c8">https://bugs.llvm.org/show_bug.cgi?id=41675#c8</a><br>
</body>
</html>