Do MI and post-RA schedulers correctly handle DBG_VALUE instructions?

Hi,

The documentation provides a couple examples of how DBG_VALUE instructions should be dealt with when moving code around.

In one example a DBG_VALUE remains in place while the tied instruction is hoisted, in the other example DBG_VALUE is duplicated and modified, and it is also mentioned that under some circumstances a DBG_VALUE can be completerly removed.

However, I can’t find the place in MI and post-RA schedulers where such transformations take place. There are ScheduleDAGMI::placeDebugValues and SchedulePostRATDList::EmitSchedule but all they do is just reinsert the debug instructions as if they were moved along with the instruction they were after.

My question is where do the mentioned DBG_VALUE transformations happen, if at all?

2 Likes

Anyone? I really can’t figure it out by myself.

Generally, the changes to debug value instructions happen directly alongside wherever the associated instructions are placed - so for example, the function MachineSink::performSink is responsible both for sinking an instruction and for duplicating and modifying dependent debug values; that function is also an example of the type of modification mentioned in the documentation. Generally speaking the preference is to leave DBG_VALUEs in place though, so that kind of transformation will usually only happen when sinking individual instructions anyway.

1 Like

Thanks. MachineSink is indeed a good example of how to work with DBG_VALUEs, and this is the point where I started learning how to work with them.

What I need is much simpler - just sink a couple instructions within a basic block (push them into the delay slot of a call instruction). So I thought I can find an example of doing something that simple in machine scheduler, as it also works on a single basic block at a time.

However, the schedulers (pre- and post-RA) do not seem to do anything which could resemble the mentioned transformations – they just move DBG_VALUEs along with the reordered instruction they originally followed. I.e. no cloning, no changing of operands, no removal.

So I was wondering if the debug information is reliable after scheduling? If so, how does it align with the documentation which explicitly says that mainaining debug info is not that simple as just moving DBG_VALUEs along with the instruction they followed? It is very likely that I’m missng something obvious.

For the purposes of your changes, I think you should consider the MachineSink approach to be correct, although depending on your code you may be able to either implement something simpler or share code with MachineSink; the most important part is changing the existing DBG_VALUEs to be undef, since that prevents the debug information from becoming incorrect at least.

In the case of the schedulers, I believe placeDebugValues does very little nowadays - it only acts on debug values that are “use before defs”, i.e. the debug value refers to an SSA value that hasn’t been defined yet; this is something of a special case that you should be able to ignore. I’m not as familiar with SchedulePostRATDList, but I’ll take a look and see if it’s doing anything wrong (and if not, then why what it’s doing is right).

the debug value refers to an SSA value that hasn’t been defined yet; this is something of a special case that you should be able to ignore.

Not sure I understood it. What do you mean by “SSA value than hasn’t been defined”?

I’ll take a look and see if it’s doing anything wrong (and if not, then why what it’s doing is right).

Thank you in advance.

I noticed that post-RA scheduler is not run at -O0. Assuming pre-RA scheduler does not do anything wrong, this can explain why programs built with clang are debuggable.

Prior to instruction selection, in the IR representation it is possible that a debug value can refer to an SSA value that is computed by an instruction that comes after the debug value, so for example:

void call @llvm.dbg.value(metadata i32 %foo, ...
...
%foo = callbr i32 ...

This rarely if ever happens at the moment, but since this patch, placeDbgValues will only apply to these cases, moving the debug value down to follow the instruction that provides its value.

Thanks, I didn’t know this.

I seem to find a patch which explains how the schedulers maintain the correct placement of DBG_VALUEs. They just don’t:

Instead, use simpler approach and let DBG_VALUE follow its predecessor instruction. After live debug value analysis pass, all DBG_VALUE instruction are placed at the right place.

@StephenTozer
Thank you very much for your help, I really appreciate it. You gave several good directions without which I would struggle much longer. Everything seems to fall into place now.