aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/IR/DebugInfoMetadata.cpp
diff options
context:
space:
mode:
authorJohn Brawn <john.brawn@arm.com>2024-06-17 12:01:08 +0100
committerGitHub <noreply@github.com>2024-06-17 12:01:08 +0100
commitf84056c38f1fd14881b23ace521a403e52ed7405 (patch)
tree8325f174fe2613cffd7fc7d5ac065ec7ce5b7864 /llvm/lib/IR/DebugInfoMetadata.cpp
parent7e4f7fcd9c0622270269d9e01031c5059cb41dae (diff)
downloadllvm-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.cpp71
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);
}