This is an archive of the discontinued LLVM Phabricator instance.

[Debuginfo][LSR} Add support for salvaging variadic dbg.value intrinsics [2/2]
ClosedPublic

Authored by chrisjackson on Feb 18 2022, 4:12 PM.

Details

Summary

Second of two patches to enable salvaging of dbg.value intrinsics that have
multiple location ops pre-LSR.

This second patch adds the core implementation. Much is shared with the
original, single-op SCEV-based salvaging. Each
optimised away location op is assigned a SCEVDbgValuebuilder that generates a
DIExpression and location ops that enable recovery of the location value. Most
of the complexity lies in creating the final location op DIArglist, because the
number of locations that will be optimised away is not known until after LSR,
and and the number of new locations that will be required to recover the
missing locations is not known until each SCEVDbgValueBuilder has generated a
recovery expression. The final DIArglist is organised as follows:

DIArglist(Induction Variable, [non optimised-out locations], [locations required for recovery expressions])

The final DIExpression is initialised empty. Its contents are formed by parsing
the original (pre-LSR) expression left-to-right, pushing each element onto the
new expression. When a DW_OP_LLVM_arg reference to an optimised-out location is
encountered, the SCEVDbgValueBuilder that recovers that location's value is
used to append both its recovery expression and values onto the final
expression and DIArglist (list contents shown above). If a reference to a
non-optimised out location is encountered, the argument index is adjusted using
a map of old to new location op indexes.

Using this method avoids any inserts and forms both the final location list and
expression with appends.

Diff Detail

Event Timeline

chrisjackson created this revision.Feb 18 2022, 4:12 PM
chrisjackson requested review of this revision.Feb 18 2022, 4:12 PM
Herald added a project: Restricted Project. · View Herald TranscriptFeb 18 2022, 4:12 PM
chrisjackson edited the summary of this revision. (Show Details)Feb 19 2022, 1:11 AM
chrisjackson edited the summary of this revision. (Show Details)Feb 19 2022, 1:14 AM
chrisjackson edited the summary of this revision. (Show Details)Feb 19 2022, 1:17 AM
djtodoro added inline comments.Feb 19 2022, 1:22 AM
llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp
6434

is the Op really const?

llvm/test/Transforms/LoopStrengthReduce/debuginfo-scev-salvage-5.ll
82–83

do we need all of these?

120–123

I guess we don't need the TBAA for the test case.

chrisjackson edited the summary of this revision. (Show Details)Feb 21 2022, 2:56 AM
davidb added a subscriber: davidb.Feb 21 2022, 5:19 AM
ormris removed a subscriber: ormris.Feb 22 2022, 10:01 AM

Removed unnecessary lit test contents as per review comments.
Fixed a comment typo in ScalarEvolution.h.

chrisjackson added inline comments.Feb 23 2022, 5:35 AM
llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp
6434

As I understand it. 'Op' itself is not modified, but its members are used to calculate a new Op for the new expression.

chrisjackson edited the summary of this revision. (Show Details)Feb 25 2022, 3:37 AM
Herald added a project: Restricted Project. · View Herald TranscriptMar 3 2022, 3:32 AM
StephenTozer added inline comments.Mar 7 2022, 7:18 AM
llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp
6159

Could this method be implemented as a more general merge of locations, so that every location in LocationOps that already appears in DestLocations is reused, rather than just the IV?

StephenTozer added inline comments.Mar 7 2022, 7:18 AM
llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp
6210

This would be better as a SmallVector pre-allocated with nullptrs imo - besides the vector having faster lookup, it also would use much less space (DenseMap automatically allocates space for 64 key+value pairs, which is 4 times as many as a DIArgList should ever actually contain).

6377–6393

Same as the above comment for RecoveryExprs, this would probably be more efficient as a SmallVector with some placeholder value for "empty" (_UI64_MAX or something to that effect).

6389

Since VH is only used in this if-block, the above check could be folded in here as if (VH && !isa<UndefValue>(VH)) {

6398

This needs to be freed at some point, could be either in the DVIRecoveryRec destructor, or this could be a unique_ptr in DVIRecoveryRec instead (which is probably safer).

6402

Thanks @StephenTozer , these are really helpful. I will be able to address them once patch [1/2] is done, which shouldn't be much longer, so hopefully I can address your comments at the end of the week.

chrisjackson added inline comments.Mar 9 2022, 2:11 PM
llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp
6159

I agree that would be the most efficient use of the location ops arguments, but at the time of writing I though this would add some additional complexity. However, it now seems not so difficult.

I had planned to to implement this in an additional patch, but I'm happy to add the functionality to this. But would it then be necessary to search the destination location vector to check if an append is necessary or location-reuse is possible?

6210

Agreed, I was concerned with the potential cost of DenseMap, though it is convenient.

6377–6393

Agreed, thanks.

6398

I thought I had taken care of this with the clear() methods. Perhaps I implemented them incorrectly. Either way, I agree unique_ptr would be nicer.

A WIP update only, not ready for a re-review. Incorporated some of @StephenTozer 's suggestions e.g.

  • replacing densemap with vector (though this still needs to be done for the location-op index)
  • making use of unique_ptr, though this had some knock-on effects on other structures -Simplified a branch in UpdateDbgValueInst

There are still several changes to make, including restoring the pre-LSR cached dbg.value correctly. I have observed that some passes will create DIArgList with a single location. This is valid, but it means extra case-handling is necessary, as the number of location-ops does not indicate the absence or presence of DIArgList, the presence of which does effect the validity of the DIExpression.

chrisjackson marked 6 inline comments as done.Mar 21 2022, 1:55 AM

Mostly refactoring of the functions that write the final salvage dbg.value. Some small corrections after a Clang-3.4 build caught a couple of corner cases (it builds fine now).

djtodoro added inline comments.Mar 22 2022, 2:45 AM
llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp
6224

clang-format please

6275

no need for the variable here, it can be inlined into the call-site

Apply @djtodoro 's change and clang-format.

chrisjackson marked an inline comment as done.

Change remaining Densemap (for updated location-op indexes) to a SmallVector.

@StephenTozer , with the exception of the location merge when appending expression and location vectors, I've completed all your suggestions. I'm keen to add that too but not in this patch, which I think is complex enough and I'm not sure how frequently locations would be duplicated. I would definitely add that in a subsequent patch but if you think that its really necessary now I can modify the append function.

Update some variable names and a couple of comments to improve readability.

chrisjackson marked 2 inline comments as done.Mar 30 2022, 3:03 AM

Good patch - I've left quite a few comments, but most of them are minor nits and some are not requirements for this patch to be merged.

llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp
5930

I suppose with the variable rename it may make sense to rename this function?

6091–6092

Nit, probably worth adding a comment for the new return value.

6159

Yeah, you'd need to check the DestLocations vector. I think it probably wouldn't be a significant performance cost to do this - the arrays are generally small (there's a relatively low hard limit on the number of ops) so it should be feasible to implement a solution in which you search DestLocations for each new LocationOp and then, if it is already present, you track that location's ArgIndex instead of adding a new one. Then you can look at that tracked index to find NewIndex. Example solution included below, though if it doesn't work and/or the problem proves more difficult than I've made it out to be then we could :

6169–6183

Example impl for the above suggestion.

6226–6230

There should probably be an assertion in this function that DW_OP_LLVM_arg appears either exactly once in the DIExpr as the first operator, or not at all. Actually, it is also possible that DW_OP_LLVM_arg, 0 could legally appear multiple times in the expression, which would be a little awkward to deal with. For example, if we salvaged the square of the IV, the expression might be DIExpr(DW_OP_LLVM_arg, 0, DW_OP_LLVM_arg, 0, DW_OP_mul).

I think the suitable answer for this patch would just be to drop such expressions for now, so that it's not a blocker. As a slight tangent though, there is a general solution possible; for an expression DIExpr([[A]], DW_OP_LLVM_arg, 0, [[B]]), it is possible to transform it to a non-variadic form like so: DIExpr(DW_OP_dup, [[A]], DW_OP_swap, [[B]]). Personally I'd be happy with this not being added in this patch though, it's a bit much imo.

6275–6277

This check could be simplified and made more correct by instead using DIExpr->isComplex(), since that also checks for DW_OP_LLVM_fragment and DW_OP_LLVM_tag_offset (which don't force stack_value). Also, as in the previous patch, it'd be better to use DIExpression's prepend function that accounts for fragments than directly appending the stack_value.

6303

Nit

6398

As above, this could use isComplex() instead.

6417
6499–6500

Doesn't need to be dealt with in this patch, just a suggestion that might be worth looking at later:

It would make sense to add an early continue here (and in the loop below) if LocOp is a constant, since we never need to salvage those ops anyway; though if DVI contains a non-SCEVable constant Op it's probably using non-SCEVable values anyway, so I don't think we'd lose many values tothise. The implementation would also touch a bunch of code around here, so is probably not worth the effort right now.

llvm/test/Transforms/LoopStrengthReduce/debuginfo-scev-salvage-5.ll
22

I think this is the fourth value now?

80–81

Can remove these I think.

chrisjackson updated this revision to Diff 420790.EditedApr 6 2022, 4:59 AM
chrisjackson marked 11 inline comments as done.

Respond to the very helpful review from @StephenTozer. Includes:

  • SCEVDbgValueBuilder.appendToVectors() now merges location vectors, preventing duplicates
  • Improved check for when a shorter DIExpression can be emitted
  • Use isComplex() instead of the size of the expression vector
llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp
6169–6183

Thanks!

6226–6230

I've added a lambda to iterate over the expression and check fo multiple DW_OP_LLVM_arg uses.

6275–6277

I don't think prepend() functions as desired here, as it will call prependOpCodes() with an empty Ops, which prevents the stack terminator being applied.

StephenTozer added inline comments.Apr 6 2022, 6:31 AM
llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp
6247

This does a good job of recognizing when the location use is complex, but it doesn't correctly handle the case where DW_OP_LLVM_arg, 0 appears later in the expression. The block for if (HasSimpleLocationUse) is correct, but the else still assumes that we just have a simple non-variadic expression. What we need is 3 different cases:

  1. Single use of arg 0 at the front: (DW_OP_LLVM_arg, 0, ...) -> Drop the first two elements of the expression.
  2. Non-variadic expression: (DW_OP_plus_uconst, 5, DW_OP_stack_value) -> Just set the unmodified expression.
  3. Complex use of arg 0: (DW_OP_LLVM_arg, 0, DW_OP_LLVM_arg, 0, ...) -> Drop the value altogether (or fixup with DW_OP_dup and DW_OP_swap, not recommended for this patch).

Right now this code handles the first two, and treats 3 the same as 2, which would result in an expression that does not use an arglist but contains DW_OP_LLVM_arg, which is currently an error.

6275–6277

My bad, that's correct - carry on. Just as long as SalvageExpression is guaranteed to not have DW_OP_stack_value already this should be fine.

Attempt to correct the final overwrite of the dbg.value, based on the count of DW_OP_llvm_arg operands in the expression.

llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp
6247

Ok, I had failed to make my intentions clear with these functions. But the method wa messy anyway, I've tried to simplify things by adding the function numLLVMArgOps that determines the number of DW_OP_LLVM_ARG ops present in an expression. The count is then used to determine if a DIArglist should be used and if the expression can be shortened. I am still not completely happy with the implementation but i think it is an improvement.

Correct diff update file.

Removed old comments, clarified messages in some asserts. Added some comments to methods.

Still a further suggestion on the most recent change - it's a minor point, but necessary I think to not produce invalid expressions. Other than that, LGTM.

llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp
6263
6269–6282

This is mostly there, but the if in the NumLLVMArgs == 1 block looks off to me, as it implies that the single DW_OP_LLVM_arg might not be the first element in NewExpr. Rather than an if, it should be an assert - I don't believe we ever produce an expression that uses DW_OP_LLVM_arg in the middle of an expression and not at the start. Alternatively, if we want to accept such expressions (which I think is quite reasonable), then they should become DBG_VALUE_LISTs rather than DBG_VALUEs. Also, if there is only one LLVM_arg in the expression then its value should definitely be 0 - anything else would be a malformed expression (we assert elsewhere that we never skip an arg index, i.e. we cannot have an expr with args [0, 1, 3] - it must be [0, 1, 2] or [0, 1, 2, 3]).

Suggested implementation included!

Made corrections to UpdateDbgValueInst() using @StephenTozer 's help.

llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp
6269–6282

I like this change a lot. I find your implementation clearer (and correct unlike mine!). I was not certain of the rules for DW_OP_LLVM_arg placement and this also makes it very clear. Thanks

StephenTozer accepted this revision.Apr 26 2022, 3:27 AM

Sorry for the delay on approving this, LGTM!

Also the last issue I brought up looks to have been present in the previous LSR salvage patch - this patch should now fix that.

This revision is now accepted and ready to land.Apr 26 2022, 3:27 AM

Note that this patch also fixes Issue #55097.

This revision was landed with ongoing or failed builds.Apr 27 2022, 4:50 AM
This revision was automatically updated to reflect the committed changes.
kstoimenov added inline comments.
llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp
6512–6522

Looks like this is being leaked. Please revert or fix your change.

Buildbot: https://lab.llvm.org/buildbot/#/builders/5/builds/22795

18095==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 304 byte(s) in 2 object(s) allocated from:

#0 0x561ec299112d in operator new(unsigned long) /b/s/w/ir/cache/builder/src/third_party/llvm/compiler-rt/lib/asan/asan_new_delete.cpp:95:3
#1 0x561ec99687f8 in DbgGatherSalvagableDVI /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp:6531:32
#2 0x561ec99687f8 in ReduceLoopStrength(llvm::Loop*, llvm::IVUsers&, llvm::ScalarEvolution&, llvm::DominatorTree&, llvm::LoopInfo&, llvm::TargetTransformInfo const&, llvm::AssumptionCache&, llvm::TargetLibraryInfo&, llvm::MemorySSA*) /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp:6592:3
#3 0x561ec99faa88 in (anonymous namespace)::LoopStrengthReduce::runOnLoop(llvm::Loop*, llvm::LPPassManager&) /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp:6680:10
#4 0x561ec6c5298f in llvm::LPPassManager::runOnFunction(llvm::Function&) /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/lib/Analysis/LoopPass.cpp:195:27
#5 0x561ec8627c77 in llvm::FPPassManager::runOnFunction(llvm::Function&) /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/lib/IR/LegacyPassManager.cpp:1430:27
#6 0x561ec86425c0 in llvm::FPPassManager::runOnModule(llvm::Module&) /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/lib/IR/LegacyPassManager.cpp:1476:16
#7 0x561ec8629b16 in runOnModule /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/lib/IR/LegacyPassManager.cpp:1545:27
#8 0x561ec8629b16 in llvm::legacy::PassManagerImpl::run(llvm::Module&) /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/lib/IR/LegacyPassManager.cpp:535:44
#9 0x561ec29ecce5 in main /b/sanitizer-x86_64-linux-fast/build/llvm-project/llvm/tools/opt/opt.cpp:1022:12
#10 0x7efe4632309a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2409a) (BuildId: eb6a5dd378d22b1e695984462a799cd4c81cdc22)
kstoimenov added inline comments.Apr 27 2022, 3:55 PM
llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp
6512–6522

This is a wrong patch. Disregard.

kstoimenov added inline comments.Apr 27 2022, 9:26 PM
llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp
6512–6522

Actually I ended up reverting it after all. The bot went green: https://lab.llvm.org/buildbot/#/builders/5/builds/22822

chrisjackson added inline comments.Apr 28 2022, 3:15 AM
llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp
6512–6522

Thanks for reverting this, I was no longer monitoring when the bot detected the leak. I'l=m working on the fix now.

  • Add managed DVIRecoveryRecords to address memory leak