PSA: IR output changing from debug intrinsics to debug records

tl;dr a patch is about to land that may break any downstream IR tests for debug info; this post explains why and how to handle it

What’s happening?

There has been a long ongoing work to replace debug intrinsics with debug records for various reasons; the purpose and design of this work is outside the scope of this post, but has been previously discussed at reasonable length(1, 2, 3), and is documented here.

This post is a warning that a patch will be landing imminently that will change the default output of LLVM from debug intrinsics to debug records. For the most part this is a straightforward mechanical change:

; Debug Intrinsic:
  call void @llvm.dbg.value(metadata i32 %add, metadata !10, metadata !DIExpression()), !dbg !20
; Debug Record:
    #dbg_value(i32 %add, !10, !DIExpression(), !20)

This applies to all the debug intrinsics, i.e. llvm.dbg.assign, llvm.dbg.declare, llvm.dbg.label, and llvm.dbg.value. As part of the patch that enables this, all upstream tests that test for debug intrinsics will be updated to test for debug records, except those that specifically seek to test debug intrinsics, essentially just verifier and IR printing/parsing tests. The patch will not update all test IR to contain debug records, only the CHECK directives, although such an update will be trivial to make if/when it happens.

What do I need to do?

All upstream tests should pass after the patch lands; I only have one machine to run the tests against however, so there may be tests that won’t run locally for me that I have missed. There will also be many downstream tests for debug intrinsics that will break after this patch lands. On the migration guide, there is a set of instructions on how to update IR tests for the new output; these instructions assume a unix shell, but if desired I could provide a translation for windows.

As a stop-gap measure it is possible to disable the use of debug records for specific tests by passing --write-experimental-debuginfo=false to LLVM’s option parser. If you have a large set of tests that are failing and aren’t able to quickly update all of them using the method above, adding this flag should quickly unblock your build. You could also do so preemptively if desired, though I highly recommend performing the update as at some point (likely in a future release) the flag will be removed. Only IR tests will be affected, so MIR and assembly/object emission will be unchanged, but this will include tests for subprojects that emit IR, e.g. clang, flang, or mlir.

3 Likes

LLVM has been using the new debug record representation for a while now. What is your plan for removing the old debug info intrinsics? Are there some blockers for their removal?

Hi – thanks for the timely question.

Using debug-records everywhere comes with a (very small) risk of error when inserting instructions at a position represented by an Instruction*. We can use the type system to protect against this by making functions like Instruction::moveBefore only take iterators as arguments, and BasicBlock::getFirstNonPHI return an iterator. Calling these functions is pervasive in any code that modifies the IR, so we figured it’d be best to mark functions using instruction-positions as deprecated for a release before deleting them.

That’s now coming up with the soon branching of LLVM 20, thus we’ve got a few PRs up that update all the relevant call-sites in LLVM to use iterator-insertion (previously we only updated the high-risk locations which we were able to scan for). If all goes to plan we can deprecate the relevant functions immediately before branching, leave it a few weeks, then remove the deprecated functions.

After that we haven’t got an exact plan for what’s next, but it would involve:

  • Deleting a wide variety of things like getNextNonDebugInstruction and similar routines
  • Shunting various conversion routines into the bitcode autoupgrade path,
  • Presumably removing DbgValueInst and similar from DebugInfoMetadata.h

A couple of years ago I measured (on the public tracker) the compile time impact of not having to test whether instructions were debug-instructions and found a 0.3% improvement for release builds; that may or may not replicate nowadays though. Additionally I didn’t consider the impact of pseudo-probes, which I believe might need similar handling to debug intrinsics. We also have some plans for future restructuring of (variable location) debug-info now that records don’t have to behave like instructions, or be stored like them.

To summarise, the branch date is a self-imposed blocker for progress, but after that we can start removing intrinsic support.

2 Likes

Hopefully final bump – intrinsic production was disabled here [0] to see whether anyone out there is still using intrinsics, and it’ll be working its way through peoples CI systems right now. We’re planning on leaving it a week and then moving on to deleting debug-intrinsic related code.

[0] [DebugInfo] Soft-disable the production of debug intrinsics (#133933) · llvm/llvm-project@6a45fce · GitHub

and then moving on to deleting debug-intrinsic related code.

Does it include parsing old debug intrinsics in IR? If so, is there some utility to convert IR tests from intrinsics to debug records automatically?

1 Like

No plans currently to disable parsing of old IR that contains debug intrinsics - even as we remove the functionality of debug intrinsics, they don’t require specialized parsing logic and so we can load them normally and then convert them to debug records. If we ever did remove parsing though, it would be trivial in most cases to update the IR tests, similar to how we updated test checks in one of the earlier pull requests.

Good, just wanted to confirm!

The DirectX backend team would be interested in any effort like this.
ATM we are planning to do a pass to convert debug records to debug intrinsics. But if there is a more general application that we could plug in to the backend that would be great. We are tracking that work here [DirectX] convert debug records to debug intrinsics · Issue #135395 · llvm/llvm-project · GitHub

Doesn’t DirectX need to convert to intrinsics in the emitted DXIL bitcode, not just adjust tests? You should be able to use the setIsNewDbgInfoFormat / convertFromNewDbgValues APIs to do that. I’d expect those to be removed later as well, but at that point they could just be sunk into the DirectX backend.

2 Likes