diff options
author | John Brawn <john.brawn@arm.com> | 2024-06-17 12:01:08 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-06-17 12:01:08 +0100 |
commit | f84056c38f1fd14881b23ace521a403e52ed7405 (patch) | |
tree | 8325f174fe2613cffd7fc7d5ac065ec7ce5b7864 /llvm/lib/IR/DebugInfoMetadata.cpp | |
parent | 7e4f7fcd9c0622270269d9e01031c5059cb41dae (diff) | |
download | llvm-f84056c38f1fd14881b23ace521a403e52ed7405.zip llvm-f84056c38f1fd14881b23ace521a403e52ed7405.tar.gz llvm-f84056c38f1fd14881b23ace521a403e52ed7405.tar.bz2 |
[DebugInfo] Handle DW_OP_LLVM_extract_bits in SROA (#94638)
This doesn't need any work to be done in SROA itself, but rather in
functions that it uses. Specifically:
* DIExpression::createFragmentExpression is made to understand
DW_OP_LLVM_extract_bits
* valueCoversEntireFragment is made to check the active bits instead of
the fragment size, so that it handles extract_bits correctly
Diffstat (limited to 'llvm/lib/IR/DebugInfoMetadata.cpp')
-rw-r--r-- | llvm/lib/IR/DebugInfoMetadata.cpp | 71 |
1 files changed, 68 insertions, 3 deletions
diff --git a/llvm/lib/IR/DebugInfoMetadata.cpp b/llvm/lib/IR/DebugInfoMetadata.cpp index 2b45932..161a30d 100644 --- a/llvm/lib/IR/DebugInfoMetadata.cpp +++ b/llvm/lib/IR/DebugInfoMetadata.cpp @@ -1679,6 +1679,41 @@ DIExpression::getFragmentInfo(expr_op_iterator Start, expr_op_iterator End) { return std::nullopt; } +std::optional<uint64_t> DIExpression::getActiveBits(DIVariable *Var) { + std::optional<uint64_t> InitialActiveBits = Var->getSizeInBits(); + std::optional<uint64_t> ActiveBits = InitialActiveBits; + for (auto Op : expr_ops()) { + switch (Op.getOp()) { + default: + // We assume the worst case for anything we don't currently handle and + // revert to the initial active bits. + ActiveBits = InitialActiveBits; + break; + case dwarf::DW_OP_LLVM_extract_bits_zext: + case dwarf::DW_OP_LLVM_extract_bits_sext: { + // We can't handle an extract whose sign doesn't match that of the + // variable. + std::optional<DIBasicType::Signedness> VarSign = Var->getSignedness(); + bool VarSigned = (VarSign == DIBasicType::Signedness::Signed); + bool OpSigned = (Op.getOp() == dwarf::DW_OP_LLVM_extract_bits_sext); + if (!VarSign || VarSigned != OpSigned) { + ActiveBits = InitialActiveBits; + break; + } + [[fallthrough]]; + } + case dwarf::DW_OP_LLVM_fragment: + // Extract or fragment narrows the active bits + if (ActiveBits) + ActiveBits = std::min(*ActiveBits, Op.getArg(1)); + else + ActiveBits = Op.getArg(1); + break; + } + } + return ActiveBits; +} + void DIExpression::appendOffset(SmallVectorImpl<uint64_t> &Ops, int64_t Offset) { if (Offset > 0) { @@ -1931,6 +1966,8 @@ std::optional<DIExpression *> DIExpression::createFragmentExpression( // Track whether it's safe to split the value at the top of the DWARF stack, // assuming that it'll be used as an implicit location value. bool CanSplitValue = true; + // Track whether we need to add a fragment expression to the end of Expr. + bool EmitFragment = true; // Copy over the expression, but leave off any trailing DW_OP_LLVM_fragment. if (Expr) { for (auto Op : Expr->expr_ops()) { @@ -1966,6 +2003,11 @@ std::optional<DIExpression *> DIExpression::createFragmentExpression( return std::nullopt; break; case dwarf::DW_OP_LLVM_fragment: { + // If we've decided we don't need a fragment then give up if we see that + // there's already a fragment expression. + // FIXME: We could probably do better here + if (!EmitFragment) + return std::nullopt; // Make the new offset point into the existing fragment. uint64_t FragmentOffsetInBits = Op.getArg(0); uint64_t FragmentSizeInBits = Op.getArg(1); @@ -1975,15 +2017,38 @@ std::optional<DIExpression *> DIExpression::createFragmentExpression( OffsetInBits += FragmentOffsetInBits; continue; } + case dwarf::DW_OP_LLVM_extract_bits_zext: + case dwarf::DW_OP_LLVM_extract_bits_sext: { + // If we're extracting bits from inside of the fragment that we're + // creating then we don't have a fragment after all, and just need to + // adjust the offset that we're extracting from. + uint64_t ExtractOffsetInBits = Op.getArg(0); + uint64_t ExtractSizeInBits = Op.getArg(1); + if (ExtractOffsetInBits >= OffsetInBits && + ExtractOffsetInBits + ExtractSizeInBits <= + OffsetInBits + SizeInBits) { + Ops.push_back(Op.getOp()); + Ops.push_back(ExtractOffsetInBits - OffsetInBits); + Ops.push_back(ExtractSizeInBits); + EmitFragment = false; + continue; + } + // If the extracted bits aren't fully contained within the fragment then + // give up. + // FIXME: We could probably do better here + return std::nullopt; + } } Op.appendToVector(Ops); } } assert((!Expr->isImplicit() || CanSplitValue) && "Expr can't be split"); assert(Expr && "Unknown DIExpression"); - Ops.push_back(dwarf::DW_OP_LLVM_fragment); - Ops.push_back(OffsetInBits); - Ops.push_back(SizeInBits); + if (EmitFragment) { + Ops.push_back(dwarf::DW_OP_LLVM_fragment); + Ops.push_back(OffsetInBits); + Ops.push_back(SizeInBits); + } return DIExpression::get(Expr->getContext(), Ops); } |