Preserving debug metadata across optimization


I've recently run into a problem of missing !dbg metadata after the
code has been optimized (even opt -O1).
The original code was generated using llvmlite python package and I've
verified that all instructions have their !dbg metadata present.
After optimizing the module (even opt -O1) I see that some
instructions (~25%) don't have any dbg metadata.
These are mostly getelementptr and bitcasts, but there's also few
One example:
  %.510.i.i = bitcast [2 x double]* %.4 to i8*
  tail call void @llvm.memset.p0i8.i64(i8* nonnull align 8 %.510.i.i, i8 0, i64 16, i1 false) #5, !dbg !2822, !alias.scope !2825, !noalias !2830

There are no memset calls in the original code. the introduced bitcast is lacking the location metadata.
The behaviour persists across llvm-6/7/git.
Is it just a series of bugs that I'm hitting?


Hi Jan,

While there’s no doubt bugs - there’s also some intentional places where debug locations are not preserved.

Specifically when moving instructions across basic blocks, debug locations are intentionally removed (again, there might be some bugs where they are /not/ removed and should be - there are always more bugs) to ensure profile accuracy (eg: if you hoist an instruction above a conditional, then a sample-based profiler sees that that line was executed it might incorrectly conclude that the condition was met when it wasn’t) & “jumpy” debugging (where your debugger goes back and forwards a lot all over the code - though, arguably, that’s accurate).

Maybe one day we’ll have a bit where we can say “this instruction was hoisted or merged” (and maybe even “this instruction comes from these 3 locations”) but for now removing the location is the best option.


thank you both.

I’ve opened a BZ at

I think it might be the case of metadata being intentionally dropped.
The situation in which it happens is when a matrix vector multiply function gets inlined and fully unrolled (due to known small dimmensions) into a caller function.
Note that the posted snippet does not produce a call to memset intrinsic. rather a set of GEPs and LOADs shed their metadata.