When a stackified variable has an associated DBG_VALUE instruction,
DebugFixup pass adds a DBG_VALUE instruction after the stackified
value's last use to clear the variable's debug range info. But when the
last use instruction is a terminator, it can cause a verification
failure (when run with -verify-machineinstrs) because there are no
instructions allowed after a terminator.
For example:
%myvar = ... DBG_VALUE target-index(wasm-operand-stack), $noreg, !"myvar", ... BR_IF 0, %myvar, ... DBG_VALUE $noreg, $noreg, !"myvar", ...
In this test, %myvar is stackified, so the first DBG_VALUE
instruction's first operand has changed to wasm-operand-stack to
denote it. And an additional DBG_VALUE instruction is added after its
last use, BR_IF, to signal variable myvar is not in the operand
stack anymore. But because the DBG_VALUE instruction is added after
the BR_IF, a terminator, it fails MachineVerifier.
I experimented on whether we could add the DBG_VALUE before the
terminator in this kind of case, but it loses info in the resulting
debug info. If we do that in the example above, the result will be:
%myvar = ... DBG_VALUE target-index(wasm-operand-stack), $noreg, !"myvar", ... DBG_VALUE $noreg, $noreg, !"myvar", ... BR_IF 0, %myvar, ...
Now the debug info for myvar has changed twice, rendering the first
DBG_VALUE meaningless. In this case this info is dropped because its
range is empty.
So this CL adds an exception for wasm in MachineVerifier's terminator
check. The reason this does not happen with other targets is, I think,
in general when DBG_VALUE has to be inserted right after an
instruction that writes to a register. If that register used to contain
a variable's value, that variable's DBG_VALUE has to be cleared. And
also if the newly written value is a value for another variable,
DBG_VALUE for that variable has to be added. But terminator
instructions don't generally write to registers, obviating the need to
add DBG_VALUEs right after them.
But wasm is special in this way, because uses, not defs, can change the
value stack location's contents. Our terminator instructions, such as
BR_IF don't write to registers but uses registers, which can be
stackified, changing the value stack and thus possibly invalidating some
variables' value in previous DBG_VALUEs, so they have to be cleared by
additional DBG_VALUEs after the terminator in that case.
I am not very familiar with how debug info works, so I might be
mistaken, and please correct me if so.
I guess the inclusion of FirstTerminator means that if there is a br_if followed by a br or whatever, then we only allow DBG_VALUE after the br_if which makes sense.
Would this miss the case where there is only one terminator (i.e. just a br, in which case it would also be the first terminator), or is FirstTerminator not set in that case?