diff --git a/llvm/include/llvm/IR/DbgVariableFragmentInfo.h b/llvm/include/llvm/IR/DbgVariableFragmentInfo.h new file mode 100644 index 0000000000000..40326d5792f9f --- /dev/null +++ b/llvm/include/llvm/IR/DbgVariableFragmentInfo.h @@ -0,0 +1,45 @@ +//===- llvm/IR/DbgVariableFragmentInfo.h ------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Helper struct to describe a fragment of a debug variable. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_IR_DBGVARIABLEFRAGMENTINFO_H +#define LLVM_IR_DBGVARIABLEFRAGMENTINFO_H + +#include + +namespace llvm { +struct DbgVariableFragmentInfo { + DbgVariableFragmentInfo() = default; + DbgVariableFragmentInfo(uint64_t SizeInBits, uint64_t OffsetInBits) + : SizeInBits(SizeInBits), OffsetInBits(OffsetInBits) {} + uint64_t SizeInBits; + uint64_t OffsetInBits; + /// Return the index of the first bit of the fragment. + uint64_t startInBits() const { return OffsetInBits; } + /// Return the index of the bit after the end of the fragment, e.g. for + /// fragment offset=16 and size=32 return their sum, 48. + uint64_t endInBits() const { return OffsetInBits + SizeInBits; } + + /// Returns a zero-sized fragment if A and B don't intersect. + static DbgVariableFragmentInfo intersect(DbgVariableFragmentInfo A, + DbgVariableFragmentInfo B) { + // Don't use std::max or min to avoid including . + uint64_t StartInBits = + A.OffsetInBits > B.OffsetInBits ? A.OffsetInBits : B.OffsetInBits; + uint64_t EndInBits = + A.endInBits() < B.endInBits() ? A.endInBits() : B.endInBits(); + if (EndInBits <= StartInBits) + return {0, 0}; + return DbgVariableFragmentInfo(EndInBits - StartInBits, StartInBits); + } +}; +} // end namespace llvm + +#endif // LLVM_IR_DBGVARIABLEFRAGMENTINFO_H diff --git a/llvm/include/llvm/IR/DebugInfoMetadata.h b/llvm/include/llvm/IR/DebugInfoMetadata.h index 524945862e8d4..d953ce46efb30 100644 --- a/llvm/include/llvm/IR/DebugInfoMetadata.h +++ b/llvm/include/llvm/IR/DebugInfoMetadata.h @@ -21,6 +21,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/iterator_range.h" #include "llvm/IR/Constants.h" +#include "llvm/IR/DbgVariableFragmentInfo.h" #include "llvm/IR/Metadata.h" #include "llvm/IR/PseudoProbe.h" #include "llvm/Support/Casting.h" @@ -2886,29 +2887,7 @@ class DIExpression : public MDNode { /// Return whether there is exactly one operator and it is a DW_OP_deref; bool isDeref() const; - /// Holds the characteristics of one fragment of a larger variable. - struct FragmentInfo { - FragmentInfo() = default; - FragmentInfo(uint64_t SizeInBits, uint64_t OffsetInBits) - : SizeInBits(SizeInBits), OffsetInBits(OffsetInBits) {} - uint64_t SizeInBits; - uint64_t OffsetInBits; - /// Return the index of the first bit of the fragment. - uint64_t startInBits() const { return OffsetInBits; } - /// Return the index of the bit after the end of the fragment, e.g. for - /// fragment offset=16 and size=32 return their sum, 48. - uint64_t endInBits() const { return OffsetInBits + SizeInBits; } - - /// Returns a zero-sized fragment if A and B don't intersect. - static DIExpression::FragmentInfo intersect(DIExpression::FragmentInfo A, - DIExpression::FragmentInfo B) { - uint64_t StartInBits = std::max(A.OffsetInBits, B.OffsetInBits); - uint64_t EndInBits = std::min(A.endInBits(), B.endInBits()); - if (EndInBits <= StartInBits) - return {0, 0}; - return DIExpression::FragmentInfo(EndInBits - StartInBits, StartInBits); - } - }; + using FragmentInfo = DbgVariableFragmentInfo; /// Return the number of bits that have an active value, i.e. those that /// aren't known to be zero/sign (depending on the type of Var) and which diff --git a/llvm/include/llvm/IR/DebugProgramInstruction.h b/llvm/include/llvm/IR/DebugProgramInstruction.h index ed8081a3cad19..734a637a4a0ee 100644 --- a/llvm/include/llvm/IR/DebugProgramInstruction.h +++ b/llvm/include/llvm/IR/DebugProgramInstruction.h @@ -50,6 +50,7 @@ #include "llvm/ADT/ilist.h" #include "llvm/ADT/ilist_node.h" #include "llvm/ADT/iterator.h" +#include "llvm/IR/DbgVariableFragmentInfo.h" #include "llvm/IR/DebugLoc.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/SymbolTableListTraits.h" @@ -460,6 +461,17 @@ class DbgVariableRecord : public DbgRecord, protected DebugValueUser { resetDebugValue(0, NewLocation); } + std::optional getFragment() const; + /// Get the FragmentInfo for the variable if it exists, otherwise return a + /// FragmentInfo that covers the entire variable if the variable size is + /// known, otherwise return a zero-sized fragment. + DbgVariableFragmentInfo getFragmentOrEntireVariable() const { + if (auto Frag = getFragment()) + return *Frag; + if (auto Sz = getVariable()->getSizeInBits()) + return {*Sz, 0}; + return {0, 0}; + } /// Get the size (in bits) of the variable, or fragment of the variable that /// is described. std::optional getFragmentSizeInBits() const; diff --git a/llvm/lib/IR/DebugProgramInstruction.cpp b/llvm/lib/IR/DebugProgramInstruction.cpp index 9a4926c81dca2..1711fd6943517 100644 --- a/llvm/lib/IR/DebugProgramInstruction.cpp +++ b/llvm/lib/IR/DebugProgramInstruction.cpp @@ -371,6 +371,10 @@ bool DbgVariableRecord::isKillLocation() const { any_of(location_ops(), [](Value *V) { return isa(V); }); } +std::optional DbgVariableRecord::getFragment() const { + return getExpression()->getFragmentInfo(); +} + std::optional DbgVariableRecord::getFragmentSizeInBits() const { if (auto Fragment = getExpression()->getFragmentInfo()) return Fragment->SizeInBits;