This is an archive of the discontinued LLVM Phabricator instance.

[DebugInfo][InstrRef] Describe value sizes when spilt to stack
ClosedPublic

Authored by jmorse on Apr 12 2022, 5:50 AM.

Details

Summary

With exciting new variable locations from instruction referencing comes exciting new ways for locations to be broken. I've run into a sample where LLVM reduces the size of an enumeration value from 32 bits to a single byte, inserting the relevant DW_OP_convert's. Unfortunately, when the single byte is spilt to the stack we describe it's location correctly, but the fact that it's only one byte is omitted. Consumers faced with a stack location and DW_OP_deref quite naturally load 32 bits from the stack instead of 8 bits, which then corrupts the variable value displayed.

The location can be correctly described with DW_OP_deref_size. This patch seeks out the size of the value and the size of the variable, and uses DW_OP_deref_size if they don't match.

While that's fairly simple, doing this stumbles into the awkward problem of whether locations should be:

  • A location expression with an implicit deref,
  • A location expression with a DW_OP_stack_value,

and we're forced to commit to one of them at this point, because it affects where the DW_OP_deref{,_size} is placed. There are then several different inputs to location-production that need to be handled. The result is a four-case if/else block, which is unfortunate, but is a gnarly problem that should be designed away at a later date.

Other test changes aside from the one added: one test needs the variable size corrected to avoid spurious changes. Another test with a FIXME is fixed (live-debug-values-restore.mir), the problem was that we have to change the expression produced for a stack slot depending on whether there's already a non-empty DIExpression. For an empty expression, adding "DW_OP_uconst, 8" and becoming a location expression with implicit deref is sufficient. But if there's something else in the expression, we have to explicitly add DW_OP_deref so that the other expression operators can operate on the loaded value. Ugly, but here we are.

Diff Detail

Event Timeline

jmorse created this revision.Apr 12 2022, 5:50 AM
Herald added a project: Restricted Project. · View Herald TranscriptApr 12 2022, 5:50 AM
jmorse requested review of this revision.Apr 12 2022, 5:50 AM
Herald added a project: Restricted Project. · View Herald TranscriptApr 12 2022, 5:50 AM

/me squints -- looks like the test doesn't cover the case of expressions with fragments, which I'll revise in later. (The patch has a case for that).

/me squints -- looks like the test doesn't cover the case of expressions with fragments, which I'll revise in later. (The patch has a case for that).

Pending the promised additional test, this LGTM with a couple of nits.

llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp
865

nit: ValueSizeInBits instead?

897

if ValueSize > VariableSize then presumably a standard DW_OP_deref would do the job? (this distinction may only save a few bytes, so may not be worth the additional case, it was just a thought).

904

nit: Any reason to use intermediate variable for the flags here but when it's not done in the other branches?

907

nit: Looks like the else if line is indented one level too few.

llvm/test/DebugInfo/MIR/InstrRef/deref-spills-with-size.mir
170
llvm/test/DebugInfo/MIR/X86/livedebugvalues_load_in_loop.mir
55

What is this change for?

jmorse planned changes to this revision.Apr 13 2022, 9:46 AM

Stone the crows, of the Dexter tests we have that originally detected this problem, another has found a problem in this patch -- for values defined in a stack slot, InstrRefBasedLDV currently guesses the size [0] because it can't work it out so late in compilation. In a piece of code dealing with vectors:

  • The variable is a "vector" class with a single array of 4 f32's, that get promoted and vectorised it seems,
  • The vectorised value is subject to a PHI at some point,
  • A DBG_INSTR_REF refers to the PHI,
  • This becomes a DBG_PHI referring to a stack slot after regalloc,
  • The code in [0] guesses that the stack slot contains 64 bits, where in reality it's 128 bits,
  • 64 bits is not the size of the variable, so a DW_OP_deref_size and DW_OP_stack_value is used, and we lose half the vector.

I think this can be solved by baking a "value size" into DBG_PHIs that refer to the stack: the register allocator knows the register class of the value spilt. We don't need to know the size of values in stack slots at any time other than when a DBG_PHI refers to it, as that's the only way DBG_INSTR_REFs can refer to stack locations. (Except for fused memory operands, which come with a size anyway...). Anyhoo, that's another patch, and more testing.

[0] https://github.com/llvm/llvm-project/blob/12a2f7494e745eb4c90133ea17cadac3a8eb8d07/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp#L1296

jmorse updated this revision to Diff 424243.Apr 21 2022, 10:20 AM

The aforementioned problems are addressed in D124184, this patch revises the test to cover scenarios where DBG_PHIs refer to the stack, and ensure that the size operand of DBG_PHI is considered.

jmorse updated this revision to Diff 424871.Apr 25 2022, 4:51 AM

Refreshed with a more comprehensive test plan -- see deref-spills-with-size.mir where there's a truth-table (well, kind of) of what inputs should lead to what output expressions, for:

  • Different sizes of value on the stack,
  • The differing presence of stack values / no stack value,
  • Whether the variable is a scalar or a fragment.

It would be nice to design some of this decision making out of DIExpression in the future, but that's for another time. This will want a little more review, as I've made one further change. For fragments with no size mistmatch, we might be able to use a DW_OP_deref and let the consumer work out "DW_OP_piece says 4 bytes, so we should dereference a 4 byte value". However it's better to be explicit and use a DW_OP_deref_size rather than leaving it to interpretation.

jmorse marked an inline comment as done.Apr 25 2022, 4:55 AM

(Addressing inline comments -- note that they've now shifted down a few lines).

llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp
897

I think in that case we get into questions about endian-ness -- it's alright on little endian I think, but not large. Rather than trying to think about that, IMO it's better to be explicit.

904

Uuuhhhh. No, purely a line wrapping consideration. I can pick one and stick to it if you've got an opinion on which way it should be.

llvm/test/DebugInfo/MIR/X86/livedebugvalues_load_in_loop.mir
55

I usually copy-and-paste metadata from other tests to avoid trimming it all over again, and then join it up with the IR / MIR that I want to test. Usually the size of the variable doesn't matter -- however

jmorse added inline comments.Apr 25 2022, 4:56 AM
llvm/test/DebugInfo/MIR/X86/livedebugvalues_load_in_loop.mir
55

... for this test it does, and so I've corrected the variable size to be 64 bits, which is how the variable is used below.

Orlando accepted this revision.Apr 26 2022, 3:42 AM

LGTM. It's great to have the comprehensive test spelling out the expectations for all the combinations of fragment / deref / indirect.

llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp
879–880

nit: if (auto Fragment = Var.getFragment()) more idiomatic?

888

nit: I think adding InBits / InBytes to these variable names would improve readability here

llvm/test/DebugInfo/MIR/InstrRef/deref-spills-with-size.mir
270
338
This revision is now accepted and ready to land.Apr 26 2022, 3:42 AM
jmorse marked 2 inline comments as done.Apr 27 2022, 1:14 AM
jmorse added inline comments.
llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp
879–880

Yup, will fold in,

888

Yup, will fold in.

This revision was landed with ongoing or failed builds.Apr 27 2022, 1:55 AM
This revision was automatically updated to reflect the committed changes.
jmorse marked 2 inline comments as done.

Hi, this seems causing crashes on our windows/mac/ios bots: https://bugs.chromium.org/p/chromium/issues/detail?id=1320808

The compressed linker repro is 4.3GB, so it's hard to upload.
here is better backtrace. Hope that helps:

Assertion failed: !Expr->isComplex(), file ../../llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp, line 907
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace.
Stack dump:
0.      Running pass 'Function Pass Manager' on module 'obj/third_party/blink/renderer/platform\platform/open_type_math_support.obj'.
1.      Running pass 'Live DEBUG_VALUE analysis' on function '@"??$GetHarfBuzzMathRecord@Uhb_ot_math_glyph_variant_t@@G@blink@@YA?AV?$Vector@G$0A@VPartitionAllocator@WTF@@@WTF@@PEBVHarfBuzzFace@0@GW4StretchAxis@OpenTypeMathStretchData@0@V?$OnceCallback@$$A6AIPEAUhb_font_t@@IW4hb_direction_t@@IPEAIPEAUhb_ot_math_glyph_variant_t@@@Z@base@@V?$RepeatingCallback@$$A6AGUhb_ot_math_glyph_variant_t@@@Z@7@V?$optional@G@absl@@@Z"'
 #0 0x00007ff79a1f2920 HandleAbort C:\src\llvm-project\llvm\lib\Support\Windows\Signals.inc:418:0
 #1 0x00007ff79da2cf53 raise C:\src\llvm-project\build\debug\minkernel\crts\ucrt\src\appcrt\misc\signal.cpp:547:0
 #2 0x00007ff79da1de3c abort C:\src\llvm-project\build\debug\minkernel\crts\ucrt\src\appcrt\startup\abort.cpp:71:0
 #3 0x00007ff79da1ed79 common_assert_to_stderr_direct C:\src\llvm-project\build\debug\minkernel\crts\ucrt\src\appcrt\startup\assert.cpp:160:0
 #4 0x00007ff79da1f05c common_assert_to_stderr<wchar_t> C:\src\llvm-project\build\debug\minkernel\crts\ucrt\src\appcrt\startup\assert.cpp:179:0
 #5 0x00007ff79da1ebce _wassert C:\src\llvm-project\build\debug\minkernel\crts\ucrt\src\appcrt\startup\assert.cpp:443:0
 #6 0x00007ff79d23175c LiveDebugValues::MLocTracker::emitLoc(class llvm::Optional<class LiveDebugValues::LocIdx>, class llvm::DebugVariable const &, class LiveDebugValues::DbgValueProperties const &) C:\src\llvm-project\llvm\lib\CodeGen\LiveDebugValues\InstrRefBasedImpl.cpp:908:0
 #7 0x00007ff79d256f33 TransferTracker::transferMlocs(class LiveDebugValues::LocIdx, class LiveDebugValues::LocIdx, class llvm::MachineInstrBundleIterator<class llvm::MachineInstr, 0>) C:\src\llvm-project\llvm\lib\CodeGen\LiveDebugValues\InstrRefBasedImpl.cpp:620:0
 #8 0x00007ff79d236839 LiveDebugValues::InstrRefBasedLDV::transferSpillOrRestoreInst::<lambda_0>::operator() C:\src\llvm-project\llvm\lib\CodeGen\LiveDebugValues\InstrRefBasedImpl.cpp:1641:0
 #9 0x00007ff79d23628a LiveDebugValues::InstrRefBasedLDV::transferSpillOrRestoreInst(class llvm::MachineInstr &) C:\src\llvm-project\llvm\lib\CodeGen\LiveDebugValues\InstrRefBasedImpl.cpp:1656:0
#10 0x00007ff79d23755a LiveDebugValues::InstrRefBasedLDV::process(class llvm::MachineInstr &, class std::unique_ptr<class LiveDebugValues::ValueIDNum[], struct std::default_delete<class LiveDebugValues::ValueIDNum[]>> const *, class std::unique_ptr<class LiveDebugValues::ValueIDNum[], struct std::default_delete<class LiveDebugValues::ValueIDNum[]>> const *) C:\src\llvm-project\llvm\lib\CodeGen\LiveDebugValues\InstrRefBasedImpl.cpp:1826:0
#11 0x00007ff79d23e3a4 LiveDebugValues::InstrRefBasedLDV::depthFirstVLocAndEmit::<lambda_0>::operator() C:\src\llvm-project\llvm\lib\CodeGen\LiveDebugValues\InstrRefBasedImpl.cpp:3015:0
#12 0x00007ff79d23e01e LiveDebugValues::InstrRefBasedLDV::depthFirstVLocAndEmit(unsigned int, class llvm::DenseMap<class llvm::LexicalScope const *, class llvm::DILocation const *, struct llvm::DenseMapInfo<class llvm::LexicalScope const *, void>, struct llvm::detail::DenseMapPair<class llvm::LexicalScope const *, class llvm::DILocation const *>> const &, class llvm::DenseMap<class llvm::LexicalScope const *, class llvm::SmallSet<class llvm::DebugVariable, 4, struct std::less<class llvm::DebugVariable>>, struct llvm::DenseMapInfo<class llvm::LexicalScope const *, void>, struct llvm::detail::DenseMapPair<class llvm::LexicalScope const *, class llvm::SmallSet<class llvm::DebugVariable, 4, struct std::less<class llvm::DebugVariable>>>> const &, class llvm::DenseMap<class llvm::LexicalScope const *, class llvm::SmallPtrSet<class llvm::MachineBasicBlock *, 4>, struct llvm::DenseMapInfo<class llvm::LexicalScope const *, void>, struct llvm::detail::DenseMapPair<class llvm::LexicalScope const *, class llvm::SmallPtrSet<class llvm::MachineBasicBlock *, 4>>> &, class llvm::SmallVector<class llvm::SmallVector<struct std::pair<class llvm::DebugVariable, class LiveDebugValues::DbgValue>, 8>, 8> &, class std::unique_ptr<class std::unique_ptr<class LiveDebugValues::ValueIDNum[], struct std::default_delete<class LiveDebugValues::ValueIDNum[]>>[], struct std::default_delete<class std::unique_ptr<class LiveDebugValues::ValueIDNum[], struct std::default_delete<class LiveDebugValues::ValueIDNum[]>>[]>> &, class std::unique_ptr<class std::unique_ptr<class LiveDebugValues::ValueIDNum[], struct std::default_delete<class LiveDebugValues::ValueIDNum[]>>[], struct std::default_delete<class std::unique_ptr<class LiveDebugValues::ValueIDNum[], struct std::default_delete<class LiveDebugValues::ValueIDNum[]>>[]>> &, class llvm::SmallVectorImpl<class LiveDebugValues::VLocTracker> &, class llvm::MachineFunction &, class llvm::DenseMap<class llvm::DebugVariable, unsigned int, struct llvm::DenseMapInfo<class llvm::DebugVariable, void>, struct llvm::detail::DenseMapPair<class llvm::DebugVariable, unsigned int>> &, class llvm::TargetPassConfig const &) C:\src\llvm-project\llvm\lib\CodeGen\LiveDebugValues\InstrRefBasedImpl.cpp:3073:0
#13 0x00007ff79d23f7c9 LiveDebugValues::InstrRefBasedLDV::ExtendRanges(class llvm::MachineFunction &, class llvm::MachineDominatorTree *, class llvm::TargetPassConfig *, unsigned int, unsigned int) C:\src\llvm-project\llvm\lib\CodeGen\LiveDebugValues\InstrRefBasedImpl.cpp:3289:0
#14 0x00007ff79bc5dd02 `anonymous namespace'::LiveDebugValues::runOnMachineFunction C:\src\llvm-project\llvm\lib\CodeGen\LiveDebugValues\LiveDebugValues.cpp:123:0
#15 0x00007ff79a88a70d llvm::MachineFunctionPass::runOnFunction(class llvm::Function &) C:\src\llvm-project\llvm\lib\CodeGen\MachineFunctionPass.cpp:73:0
#16 0x00007ff79ab02e52 llvm::FPPassManager::runOnFunction(class llvm::Function &) C:\src\llvm-project\llvm\lib\IR\LegacyPassManager.cpp:1430:0
#17 0x00007ff79ab0808e llvm::FPPassManager::runOnModule(class llvm::Module &) C:\src\llvm-project\llvm\lib\IR\LegacyPassManager.cpp:1476:0
#18 0x00007ff79ab03810 `anonymous namespace'::MPPassManager::runOnModule C:\src\llvm-project\llvm\lib\IR\LegacyPassManager.cpp:1545:0
#19 0x00007ff79ab032f0 llvm::legacy::PassManagerImpl::run(class llvm::Module &) C:\src\llvm-project\llvm\lib\IR\LegacyPassManager.cpp:535:0
#20 0x00007ff79ab08361 llvm::legacy::PassManager::run(class llvm::Module &) C:\src\llvm-project\llvm\lib\IR\LegacyPassManager.cpp:1672:0
#21 0x00007ff79a4cfda0 codegen C:\src\llvm-project\llvm\lib\LTO\LTOBackend.cpp:392:0
#22 0x00007ff79a4d09ea llvm::lto::thinBackend::<lambda_0>::operator() C:\src\llvm-project\llvm\lib\LTO\LTOBackend.cpp:559:0
#23 0x00007ff79a4d081d llvm::lto::thinBackend(struct llvm::lto::Config const &, unsigned int, class std::function<(unsigned int)>, class llvm::Module &, class llvm::ModuleSummaryIndex const &, class llvm::StringMap<class std::unordered_set<unsigned __int64, struct std::hash<unsigned __int64>, struct std::equal_to<unsigned __int64>, class std::allocator<unsigned __int64>>, class llvm::MallocAllocator> const &, class llvm::DenseMap<unsigned __int64, class llvm::GlobalValueSummary *, struct llvm::DenseMapInfo<unsigned __int64, void>, struct llvm::detail::DenseMapPair<unsigned __int64, class llvm::GlobalValueSummary *>> const &, class llvm::MapVector<class llvm::StringRef, class llvm::BitcodeModule, class llvm::DenseMap<class llvm::StringRef, unsigned int, struct llvm::DenseMapInfo<class llvm::StringRef, void>, struct llvm::detail::DenseMapPair<class llvm::StringRef, unsigned int>>, class std::vector<struct std::pair<class llvm::StringRef, class llvm::BitcodeModule>, class std::allocator<struct std::pair<class llvm::StringRef, class llvm::BitcodeModule>>>> *, class std::vector<unsigned char, class std::allocator<unsigned char>> const &) C:\src\llvm-project\llvm\lib\LTO\LTOBackend.cpp:630:0
#24 0x00007ff799d02c5d `anonymous namespace'::InProcessThinBackend::runThinLTOBackendThread::<lambda_1>::operator() C:\src\llvm-project\llvm\lib\LTO\LTO.cpp:1223:0
#25 0x00007ff799d029aa `anonymous namespace'::InProcessThinBackend::runThinLTOBackendThread C:\src\llvm-project\llvm\lib\LTO\LTO.cpp:1246:0
#26 0x00007ff799d02488 `anonymous namespace'::InProcessThinBackend::start::<lambda_1>::operator() C:\src\llvm-project\llvm\lib\LTO\LTO.cpp:1275:0
#27 0x00007ff799d022b4 std::invoke<`lambda at ../../llvm/lib/LTO/LTO.cpp:1262:9' &,llvm::BitcodeModule &,llvm::ModuleSummaryIndex &,const llvm::StringMap<std::unordered_set<unsigned long long,std::hash<unsigned long long>,std::equal_to<unsigned long long>,std::allocator<unsigned long long> >,llvm::MallocAllocator> &,const llvm::DenseSet<llvm::ValueInfo,llvm::DenseMapInfo<llvm::ValueInfo,void> > &,const std::map<unsigned long long,llvm::GlobalValue::LinkageTypes,std::less<unsigned long long>,std::allocator<std::pair<const unsigned long long,llvm::GlobalValue::LinkageTypes> > > &,const llvm::DenseMap<unsigned long long,llvm::GlobalValueSummary *,llvm::DenseMapInfo<unsigned long long,void>,llvm::detail::DenseMapPair<unsigned long long,llvm::GlobalValueSummary *> > &,llvm::MapVector<llvm::StringRef,llvm::BitcodeModule,llvm::DenseMap<llvm::StringRef,unsigned int,llvm::DenseMapInfo<llvm::StringRef,void>,llvm::detail::DenseMapPair<llvm::StringRef,unsigned int> >,std::vector<std::pair<llvm::StringRef,llvm::BitcodeModule>,std::allocator<std::pair<llvm::StringRef,llvm::BitcodeModule> > > > &> C:\src\llvm-project\chrome-sysroot\VC\Tools\MSVC\14.29.30133\include\type_traits:1595:0
#28 0x00007ff799d021a6 std::_Invoker_ret<std::_Unforced,0>::_Call<`lambda at ../../llvm/lib/LTO/LTO.cpp:1262:9' &,llvm::BitcodeModule &,llvm::ModuleSummaryIndex &,const llvm::StringMap<std::unordered_set<unsigned long long,std::hash<unsigned long long>,std::equal_to<unsigned long long>,std::allocator<unsigned long long> >,llvm::MallocAllocator> &,const llvm::DenseSet<llvm::ValueInfo,llvm::DenseMapInfo<llvm::ValueInfo,void> > &,const std::map<unsigned long long,llvm::GlobalValue::LinkageTypes,std::less<unsigned long long>,std::allocator<std::pair<const unsigned long long,llvm::GlobalValue::LinkageTypes> > > &,const llvm::DenseMap<unsigned long long,llvm::GlobalValueSummary *,llvm::DenseMapInfo<unsigned long long,void>,llvm::detail::DenseMapPair<unsigned long long,llvm::GlobalValueSummary *> > &,llvm::MapVector<llvm::StringRef,llvm::BitcodeModule,llvm::DenseMap<llvm::StringRef,unsigned int,llvm::DenseMapInfo<llvm::StringRef,void>,llvm::detail::DenseMapPair<llvm::StringRef,unsigned int> >,std::vector<std::pair<llvm::StringRef,llvm::BitcodeModule>,std::allocator<std::pair<llvm::StringRef,llvm::BitcodeModule> > > > &> C:\src\llvm-project\chrome-sysroot\VC\Tools\MSVC\14.29.30133\include\functional:763:0
#29 0x00007ff799d02100 std::_Call_binder<std::_Unforced,0,1,2,3,4,5,6,`lambda at ../../llvm/lib/LTO/LTO.cpp:1262:9',std::tuple<llvm::BitcodeModule,std::reference_wrapper<llvm::ModuleSummaryIndex>,std::reference_wrapper<const llvm::StringMap<std::unordered_set<unsigned long long,std::hash<unsigned long long>,std::equal_to<unsigned long long>,std::allocator<unsigned long long> >,llvm::MallocAllocator> >,std::reference_wrapper<const llvm::DenseSet<llvm::ValueInfo,llvm::DenseMapInfo<llvm::ValueInfo,void> > >,std::reference_wrapper<const std::map<unsigned long long,llvm::GlobalValue::LinkageTypes,std::less<unsigned long long>,std::allocator<std::pair<const unsigned long long,llvm::GlobalValue::LinkageTypes> > > >,std::reference_wrapper<const llvm::DenseMap<unsigned long long,llvm::GlobalValueSummary *,llvm::DenseMapInfo<unsigned long long,void>,llvm::detail::DenseMapPair<unsigned long long,llvm::GlobalValueSummary *> > >,std::reference_wrapper<llvm::MapVector<llvm::StringRef,llvm::BitcodeModule,llvm::DenseMap<llvm::StringRef,unsigned int,llvm::DenseMapInfo<llvm::StringRef,void>,llvm::detail::DenseMapPair<llvm::StringRef,unsigned int> >,std::vector<std::pair<llvm::StringRef,llvm::BitcodeModule>,std::allocator<std::pair<llvm::StringRef,llvm::BitcodeModule> > > > > >,std::tuple<> > C:\src\llvm-project\chrome-sysroot\VC\Tools\MSVC\14.29.30133\include\functional:1414:0
#30 0x00007ff799d01f31 std::_Binder<std::_Unforced,`lambda at ../../llvm/lib/LTO/LTO.cpp:1262:9',llvm::BitcodeModule &,std::reference_wrapper<llvm::ModuleSummaryIndex>,std::reference_wrapper<const llvm::StringMap<std::unordered_set<unsigned long long,std::hash<unsigned long long>,std::equal_to<unsigned long long>,std::allocator<unsigned long long> >,llvm::MallocAllocator> >,std::reference_wrapper<const llvm::DenseSet<llvm::ValueInfo,llvm::DenseMapInfo<llvm::ValueInfo,void> > >,std::reference_wrapper<const std::map<unsigned long long,llvm::GlobalValue::LinkageTypes,std::less<unsigned long long>,std::allocator<std::pair<const unsigned long long,llvm::GlobalValue::LinkageTypes> > > >,std::reference_wrapper<const llvm::DenseMap<unsigned long long,llvm::GlobalValueSummary *,llvm::DenseMapInfo<unsigned long long,void>,llvm::detail::DenseMapPair<unsigned long long,llvm::GlobalValueSummary *> > >,std::reference_wrapper<llvm::MapVector<llvm::StringRef,llvm::BitcodeModule,llvm::DenseMap<llvm::StringRef,unsigned int,llvm::DenseMapInfo<llvm::StringRef,void>,llvm::detail::DenseMapPair<llvm::StringRef,unsigned int> >,std::vector<std::pair<llvm::StringRef,llvm::BitcodeModule>,std::allocator<std::pair<llvm::StringRef,llvm::BitcodeModule> > > > > >::operator()<> C:\src\llvm-project\chrome-sysroot\VC\Tools\MSVC\14.29.30133\include\functional:1452:0
#31 0x00007ff799d01ec3 std::invoke<std::_Binder<std::_Unforced,`lambda at ../../llvm/lib/LTO/LTO.cpp:1262:9',llvm::BitcodeModule &,std::reference_wrapper<llvm::ModuleSummaryIndex>,std::reference_wrapper<const llvm::StringMap<std::unordered_set<unsigned long long,std::hash<unsigned long long>,std::equal_to<unsigned long long>,std::allocator<unsigned long long> >,llvm::MallocAllocator> >,std::reference_wrapper<const llvm::DenseSet<llvm::ValueInfo,llvm::DenseMapInfo<llvm::ValueInfo,void> > >,std::reference_wrapper<const std::map<unsigned long long,llvm::GlobalValue::LinkageTypes,std::less<unsigned long long>,std::allocator<std::pair<const unsigned long long,llvm::GlobalValue::LinkageTypes> > > >,std::reference_wrapper<const llvm::DenseMap<unsigned long long,llvm::GlobalValueSummary *,llvm::DenseMapInfo<unsigned long long,void>,llvm::detail::DenseMapPair<unsigned long long,llvm::GlobalValueSummary *> > >,std::reference_wrapper<llvm::MapVector<llvm::StringRef,llvm::BitcodeModule,llvm::DenseMap<llvm::StringRef,unsigned int,llvm::DenseMapInfo<llvm::StringRef,void>,llvm::detail::DenseMapPair<llvm::StringRef,unsigned int> >,std::vector<std::pair<llvm::StringRef,llvm::BitcodeModule>,std::allocator<std::pair<llvm::StringRef,llvm::BitcodeModule> > > > > > &> C:\src\llvm-project\chrome-sysroot\VC\Tools\MSVC\14.29.30133\include\type_traits:1585:0
#32 0x00007ff799d01ea3 std::_Invoker_ret<void,1>::_Call<std::_Binder<std::_Unforced,`lambda at ../../llvm/lib/LTO/LTO.cpp:1262:9',llvm::BitcodeModule &,std::reference_wrapper<llvm::ModuleSummaryIndex>,std::reference_wrapper<const llvm::StringMap<std::unordered_set<unsigned long long,std::hash<unsigned long long>,std::equal_to<unsigned long long>,std::allocator<unsigned long long> >,llvm::MallocAllocator> >,std::reference_wrapper<const llvm::DenseSet<llvm::ValueInfo,llvm::DenseMapInfo<llvm::ValueInfo,void> > >,std::reference_wrapper<const std::map<unsigned long long,llvm::GlobalValue::LinkageTypes,std::less<unsigned long long>,std::allocator<std::pair<const unsigned long long,llvm::GlobalValue::LinkageTypes> > > >,std::reference_wrapper<const llvm::DenseMap<unsigned long long,llvm::GlobalValueSummary *,llvm::DenseMapInfo<unsigned long long,void>,llvm::detail::DenseMapPair<unsigned long long,llvm::GlobalValueSummary *> > >,std::reference_wrapper<llvm::MapVector<llvm::StringRef,llvm::BitcodeModule,llvm::DenseMap<llvm::StringRef,unsigned int,llvm::DenseMapInfo<llvm::StringRef,void>,llvm::detail::DenseMapPair<llvm::StringRef,unsigned int> >,std::vector<std::pair<llvm::StringRef,llvm::BitcodeModule>,std::allocator<std::pair<llvm::StringRef,llvm::BitcodeModule> > > > > > &> C:\src\llvm-project\chrome-sysroot\VC\Tools\MSVC\14.29.30133\include\functional:745:0
#33 0x00007ff799d01c97 std::_Func_impl_no_alloc<std::_Binder<std::_Unforced,`lambda at ../../llvm/lib/LTO/LTO.cpp:1262:9',llvm::BitcodeModule &,std::reference_wrapper<llvm::ModuleSummaryIndex>,std::reference_wrapper<const llvm::StringMap<std::unordered_set<unsigned long long,std::hash<unsigned long long>,std::equal_to<unsigned long long>,std::allocator<unsigned long long> >,llvm::MallocAllocator> >,std::reference_wrapper<const llvm::DenseSet<llvm::ValueInfo,llvm::DenseMapInfo<llvm::ValueInfo,void> > >,std::reference_wrapper<const std::map<unsigned long long,llvm::GlobalValue::LinkageTypes,std::less<unsigned long long>,std::allocator<std::pair<const unsigned long long,llvm::GlobalValue::LinkageTypes> > > >,std::reference_wrapper<const llvm::DenseMap<unsigned long long,llvm::GlobalValueSummary *,llvm::DenseMapInfo<unsigned long long,void>,llvm::detail::DenseMapPair<unsigned long long,llvm::GlobalValueSummary *> > >,std::reference_wrapper<llvm::MapVector<llvm::StringRef,llvm::BitcodeModule,llvm::DenseMap<llvm::StringRef,unsigned int,llvm::DenseMapInfo<llvm::StringRef,void>,llvm::detail::DenseMapPair<llvm::StringRef,unsigned int> >,std::vector<std::pair<llvm::StringRef,llvm::BitcodeModule>,std::allocator<std::pair<llvm::StringRef,llvm::BitcodeModule> > > > > >,void>::_Do_call C:\src\llvm-project\chrome-sysroot\VC\Tools\MSVC\14.29.30133\include\functional:920:0
#34 0x00007ff799b4fd34 std::_Func_class<void>::operator()(void) const C:\src\llvm-project\chrome-sysroot\VC\Tools\MSVC\14.29.30133\include\functional:968:0
#35 0x00007ff799d3a5ec `private: static struct std::pair<class std::function<void __cdecl(void)>, class std::future<void>> __cdecl llvm::ThreadPool::createTaskAndFuture(class std::function<void __cdecl(void)>)'::`1'::<lambda_1>::operator()(void) const C:\src\llvm-project\llvm\include\llvm\Support\ThreadPool.h:95:0
#36 0x00007ff799d3a5c3 std::invoke<class `private: static struct std::pair<class std::function<void __cdecl(void)>, class std::future<void>> __cdecl llvm::ThreadPool::createTaskAndFuture(class std::function<void __cdecl(void)>)'::`1'::<lambda_1> &>(class `private: static struct std::pair<class std::function<void __cdecl(void)>, class std::future<void>> __cdecl llvm::ThreadPool::createTaskAndFuture(class std::function<void __cdecl(void)>)'::`1'::<lambda_1> &) C:\src\llvm-project\chrome-sysroot\VC\Tools\MSVC\14.29.30133\include\type_traits:1585:0
#37 0x00007ff799d3a5a3 std::_Invoker_ret<void, 1>::_Call<class `private: static struct std::pair<class std::function<void __cdecl(void)>, class std::future<void>> __cdecl llvm::ThreadPool::createTaskAndFuture(class std::function<void __cdecl(void)>)'::`1'::<lambda_1> &>(class `private: static struct std::pair<class std::function<void __cdecl(void)>, class std::future<void>> __cdecl llvm::ThreadPool::createTaskAndFuture(class std::function<void __cdecl(void)>)'::`1'::<lambda_1> &) C:\src\llvm-project\chrome-sysroot\VC\Tools\MSVC\14.29.30133\include\functional:745:0
#38 0x00007ff799d3a2f7 std::_Func_impl_no_alloc<class `private: static struct std::pair<class std::function<void __cdecl(void)>, class std::future<void>> __cdecl llvm::ThreadPool::createTaskAndFuture(class std::function<void __cdecl(void)>)'::`1'::<lambda_1>, void>::_Do_call(void) C:\src\llvm-project\chrome-sysroot\VC\Tools\MSVC\14.29.30133\include\functional:920:0
#39 0x00007ff799b4fd34 std::_Func_class<void>::operator()(void) const C:\src\llvm-project\chrome-sysroot\VC\Tools\MSVC\14.29.30133\include\functional:968:0
#40 0x00007ff79a5fba7c llvm::ThreadPool::grow::<lambda_0>::operator() C:\src\llvm-project\llvm\lib\Support\ThreadPool.cpp:59:0
#41 0x00007ff79a5fb93f llvm::thread::Apply<`lambda at ../../llvm/lib/Support/ThreadPool.cpp:37:26'> C:\src\llvm-project\llvm\include\llvm\Support\thread.h:43:0
#42 0x00007ff79a5fb8f7 llvm::thread::GenericThreadProxy<std::tuple<`lambda at ../../llvm/lib/Support/ThreadPool.cpp:37:26'> > C:\src\llvm-project\llvm\include\llvm\Support\thread.h:51:0
#43 0x00007ff79a5fb773 llvm::thread::ThreadProxy<std::tuple<`lambda at ../../llvm/lib/Support/ThreadPool.cpp:37:26'> > C:\src\llvm-project\llvm\include\llvm\Support\thread.h:71:0
#44 0x00007ff79da1569e thread_start<unsigned int (__cdecl*)(void *),1> C:\src\llvm-project\build\debug\minkernel\crts\ucrt\src\appcrt\startup\thread.cpp:97:0
#45 0x00007ffdf8087034 (C:\Windows\System32\KERNEL32.DLL+0x17034)
#46 0x00007ffdf8ce2651 (C:\Windows\SYSTEM32\ntdll.dll+0x52651)

Thanks for reverting; I think this has uncovered some changes in my assumptions of how some variable locations are described. Would you happen to know whether the source being compiled contains coroutines? There's been some work there lately which might have had an effect.

To explain my thinking -- coroutines recently started using dbg.addr, and can be salvaged in 0b647fc529, which will create complex DIExpressions (aka anything with a DW_OP_stack_value). I think this might be the first scenario where dbg.addrs are generated and can be salvaged, which then messes up other code I've written in SelectionDAG, that assumes a dbg.addr can be treated as a more specific dbg.declare. If so, the fix is probably to flush the indirectness out of the intrinsics/instructions at SelectionDAG, seeing how everyone wants the IsIndirect flag gone in the long run.

jmorse updated this revision to Diff 426081.Apr 29 2022, 9:10 AM

Thinking about it, actually we can easily support the llvm.dbg.addr with complex-expression scenario, just by weakening the assertion that's firing. The code as written will cope just fine with dbg.addrs that perform a computation, the true problem is when there's a DW_OP_stack_value in the expression. That's what this assertion should have been testing for in the first place. It doesn't make sense for a variable to both be indirect, and computed on the DWARF expression stack.

I've revised the patch to weaken the assertion, and added a test to cover the situation I described, an indirect DBG_VALUE with extra opcodes, but no stack value. There are two dereferences in this situation, and we need to make sure they're performed at the right time.

Paging @Orlando , if you could review the update.

jmorse reopened this revision.Apr 29 2022, 9:10 AM
This revision is now accepted and ready to land.Apr 29 2022, 9:10 AM
jmorse requested review of this revision.Apr 29 2022, 9:10 AM

Thanks for the reproducer; while it's mildly hard to interpret what's going on, I think a large block of local stack memory that's the subject of a dbg.declare, is being recorded by a

DBG_VALUE %fixed.stack.0, 0, !123, !DIExpression()

In the entry block, rather than being put in the side-table. That then gets translated by the prolog/epilog pass into an indirect DBG_VALUE with an offset added, which then hits this assertion. Happily, I think this too falls into the category of "the assertion is over-zealous" I described above, and can be handled just by the modifications I've made in the revised patch. Woo.

Orlando accepted this revision.May 9 2022, 2:01 AM

The latest change makes sense, LGTM

This revision is now accepted and ready to land.May 9 2022, 2:01 AM
This revision was landed with ongoing or failed builds.May 12 2022, 7:53 AM
This revision was automatically updated to reflect the committed changes.