aboutsummaryrefslogtreecommitdiff
path: root/llvm
diff options
context:
space:
mode:
Diffstat (limited to 'llvm')
-rw-r--r--llvm/include/llvm/IR/BasicBlock.h54
-rw-r--r--llvm/include/llvm/IR/DebugInfoMetadata.h4
-rw-r--r--llvm/include/llvm/IR/DebugProgramInstruction.h378
-rw-r--r--llvm/include/llvm/IR/Function.h16
-rw-r--r--llvm/include/llvm/IR/Instruction.h8
-rw-r--r--llvm/include/llvm/IR/Metadata.h99
-rw-r--r--llvm/include/llvm/IR/Module.h21
-rw-r--r--llvm/lib/IR/BasicBlock.cpp185
-rw-r--r--llvm/lib/IR/CMakeLists.txt1
-rw-r--r--llvm/lib/IR/DebugInfoMetadata.cpp18
-rw-r--r--llvm/lib/IR/DebugProgramInstruction.cpp353
-rw-r--r--llvm/lib/IR/Function.cpp23
-rw-r--r--llvm/lib/IR/LLVMContextImpl.cpp8
-rw-r--r--llvm/lib/IR/LLVMContextImpl.h31
-rw-r--r--llvm/lib/IR/Metadata.cpp70
-rw-r--r--llvm/lib/IR/Module.cpp3
-rw-r--r--llvm/lib/IR/Verifier.cpp8
-rw-r--r--llvm/lib/Linker/IRMover.cpp3
-rw-r--r--llvm/lib/Target/AMDGPU/AMDGPURewriteOutArguments.cpp2
-rw-r--r--llvm/lib/Transforms/IPO/ArgumentPromotion.cpp1
-rw-r--r--llvm/lib/Transforms/IPO/DeadArgumentElimination.cpp2
-rw-r--r--llvm/lib/Transforms/Utils/CloneFunction.cpp2
-rw-r--r--llvm/unittests/IR/DebugInfoTest.cpp309
-rw-r--r--llvm/unittests/Transforms/Utils/LocalTest.cpp67
-rw-r--r--llvm/utils/gn/secondary/llvm/lib/IR/BUILD.gn1
25 files changed, 1658 insertions, 9 deletions
diff --git a/llvm/include/llvm/IR/BasicBlock.h b/llvm/include/llvm/IR/BasicBlock.h
index ab291c2..a6d66d1 100644
--- a/llvm/include/llvm/IR/BasicBlock.h
+++ b/llvm/include/llvm/IR/BasicBlock.h
@@ -36,6 +36,8 @@ class LLVMContext;
class Module;
class PHINode;
class ValueSymbolTable;
+class DPValue;
+class DPMarker;
/// LLVM Basic Block Representation
///
@@ -56,6 +58,9 @@ class BasicBlock final : public Value, // Basic blocks are data objects also
public ilist_node_with_parent<BasicBlock, Function> {
public:
using InstListType = SymbolTableList<Instruction, ilist_iterator_bits<true>>;
+ /// Flag recording whether or not this block stores debug-info in the form
+ /// of intrinsic instructions (false) or non-instruction records (true).
+ bool IsNewDbgInfoFormat;
private:
friend class BlockAddress;
@@ -64,6 +69,55 @@ private:
InstListType InstList;
Function *Parent;
+public:
+ /// Attach a DPMarker to the given instruction. Enables the storage of any
+ /// debug-info at this position in the program.
+ DPMarker *createMarker(Instruction *I);
+ DPMarker *createMarker(InstListType::iterator It);
+
+ /// Convert variable location debugging information stored in dbg.value
+ /// intrinsics into DPMarker / DPValue records. Deletes all dbg.values in
+ /// the process and sets IsNewDbgInfoFormat = true. Only takes effect if
+ /// the UseNewDbgInfoFormat LLVM command line option is given.
+ void convertToNewDbgValues();
+
+ /// Convert variable location debugging information stored in DPMarkers and
+ /// DPValues into the dbg.value intrinsic representation. Sets
+ /// IsNewDbgInfoFormat = false.
+ void convertFromNewDbgValues();
+
+ /// Ensure the block is in "old" dbg.value format (\p NewFlag == false) or
+ /// in the new format (\p NewFlag == true), converting to the desired format
+ /// if necessary.
+ void setIsNewDbgInfoFormat(bool NewFlag);
+
+ /// Validate any DPMarkers / DPValues attached to instructions in this block,
+ /// and block-level stored data too (TrailingDPValues).
+ /// \p Assert Should this method fire an assertion if a problem is found?
+ /// \p Msg Should this method print a message to errs() if a problem is found?
+ /// \p OS Output stream to write errors to.
+ /// \returns True if a problem is found.
+ bool validateDbgValues(bool Assert = true, bool Msg = false,
+ raw_ostream *OS = nullptr);
+
+ /// Record that the collection of DPValues in \p M "trails" after the last
+ /// instruction of this block. These are equivalent to dbg.value intrinsics
+ /// that exist at the end of a basic block with no terminator (a transient
+ /// state that occurs regularly).
+ void setTrailingDPValues(DPMarker *M);
+
+ /// Fetch the collection of DPValues that "trail" after the last instruction
+ /// of this block, see \ref setTrailingDPValues. If there are none, returns
+ /// nullptr.
+ DPMarker *getTrailingDPValues();
+
+ /// Delete any trailing DPValues at the end of this block, see
+ /// \ref setTrailingDPValues.
+ void deleteTrailingDPValues();
+
+ void dumpDbgValues() const;
+
+private:
void setParent(Function *parent);
/// Constructor.
diff --git a/llvm/include/llvm/IR/DebugInfoMetadata.h b/llvm/include/llvm/IR/DebugInfoMetadata.h
index b347664..1fe0543 100644
--- a/llvm/include/llvm/IR/DebugInfoMetadata.h
+++ b/llvm/include/llvm/IR/DebugInfoMetadata.h
@@ -3765,6 +3765,10 @@ public:
iterator args_begin() { return Args.begin(); }
iterator args_end() { return Args.end(); }
+ ReplaceableMetadataImpl *getReplaceableUses() {
+ return Context.getReplaceableUses();
+ }
+
static bool classof(const Metadata *MD) {
return MD->getMetadataID() == DIArgListKind;
}
diff --git a/llvm/include/llvm/IR/DebugProgramInstruction.h b/llvm/include/llvm/IR/DebugProgramInstruction.h
new file mode 100644
index 0000000..fef4bb6
--- /dev/null
+++ b/llvm/include/llvm/IR/DebugProgramInstruction.h
@@ -0,0 +1,378 @@
+//===-- llvm/DebugProgramInstruction.h - Stream of debug info -------*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Data structures for storing variable assignment information in LLVM. In the
+// dbg.value design, a dbg.value intrinsic specifies the position in a block
+// a source variable take on an LLVM Value:
+//
+// %foo = add i32 1, %0
+// dbg.value(metadata i32 %foo, ...)
+// %bar = void call @ext(%foo);
+//
+// and all information is stored in the Value / Metadata hierachy defined
+// elsewhere in LLVM. In the "DPValue" design, each instruction /may/ have a
+// connection with a DPMarker, which identifies a position immediately before the
+// instruction, and each DPMarker /may/ then have connections to DPValues which
+// record the variable assignment information. To illustrate:
+//
+// %foo = add i32 1, %0
+// ; foo->DbgMarker == nullptr
+// ;; There are no variable assignments / debug records "in front" of
+// ;; the instruction for %foo, therefore it has no DbgMarker.
+// %bar = void call @ext(%foo)
+// ; bar->DbgMarker = {
+// ; StoredDPValues = {
+// ; DPValue(metadata i32 %foo, ...)
+// ; }
+// ; }
+// ;; There is a debug-info record in front of the %bar instruction,
+// ;; thus it points at a DPMarker object. That DPMarker contains a
+// ;; DPValue in it's ilist, storing the equivalent information to the
+// ;; dbg.value above: the Value, DILocalVariable, etc.
+//
+// This structure separates the two concerns of the position of the debug-info
+// in the function, and the Value that it refers to. It also creates a new
+// "place" in-between the Value / Metadata hierachy where we can customise
+// storage and allocation techniques to better suite debug-info workloads.
+// NB: as of the initial prototype, none of that has actually been attempted
+// yet.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_IR_DEBUGPROGRAMINSTRUCTION_H
+#define LLVM_IR_DEBUGPROGRAMINSTRUCTION_H
+
+#include "llvm/ADT/ilist_node.h"
+#include "llvm/ADT/ilist.h"
+#include "llvm/ADT/iterator.h"
+#include "llvm/IR/DebugInfoMetadata.h"
+#include "llvm/IR/DebugLoc.h"
+#include <cstdint>
+#include <utility>
+
+namespace llvm {
+
+class Instruction;
+class BasicBlock;
+class MDNode;
+class Module;
+class DbgVariableIntrinsic;
+class DPMarker;
+class DPValue;
+class raw_ostream;
+
+/// Record of a variable value-assignment, aka a non instruction representation
+/// of the dbg.value intrinsic. Features various methods copied across from the
+/// Instruction class to aid ease-of-use. DPValue objects should always be
+/// linked into a DPMarker's StoredDPValues list. The marker connects a DPValue
+/// back to it's position in the BasicBlock.
+///
+/// This class inherits from DebugValueUser to allow LLVM's metadata facilities
+/// to update our references to metadata beneath our feet.
+class DPValue : public ilist_node<DPValue>, private DebugValueUser {
+ friend class DebugValueUser;
+
+ // NB: there is no explicit "Value" field in this class, it's effectively the
+ // DebugValueUser superclass instead. The referred to Value can either be a
+ // ValueAsMetadata or a DIArgList.
+
+ DILocalVariable *Variable;
+ DIExpression *Expression;
+ DebugLoc DbgLoc;
+
+public:
+ void deleteInstr();
+
+ const BasicBlock *getParent() const;
+ BasicBlock *getParent();
+ void dump() const;
+ void removeFromParent();
+ void eraseFromParent();
+
+ using self_iterator = simple_ilist<DPValue>::iterator;
+ using const_self_iterator = simple_ilist<DPValue>::const_iterator;
+
+ enum class LocationType {
+ Declare,
+ Value,
+ };
+ /// Classification of the debug-info record that this DPValue represents.
+ /// Essentially, "is this a dbg.value or dbg.declare?". dbg.declares are not
+ /// currently supported, but it would be trivial to do so.
+ LocationType Type;
+
+ /// Marker that this DPValue is linked into.
+ DPMarker *Marker = nullptr;
+
+ /// Create a new DPValue representing the intrinsic \p DVI, for example the
+ /// assignment represented by a dbg.value.
+ DPValue(const DbgVariableIntrinsic *DVI);
+ DPValue(const DPValue &DPV);
+ /// Directly construct a new DPValue representing a dbg.value intrinsic
+ /// assigning \p Location to the DV / Expr / DI variable.
+ DPValue(Metadata *Location, DILocalVariable *DV, DIExpression *Expr,
+ const DILocation *DI);
+
+ /// Iterator for ValueAsMetadata that internally uses direct pointer iteration
+ /// over either a ValueAsMetadata* or a ValueAsMetadata**, dereferencing to the
+ /// ValueAsMetadata .
+ class location_op_iterator
+ : public iterator_facade_base<location_op_iterator,
+ std::bidirectional_iterator_tag, Value *> {
+ PointerUnion<ValueAsMetadata *, ValueAsMetadata **> I;
+
+ public:
+ location_op_iterator(ValueAsMetadata *SingleIter) : I(SingleIter) {}
+ location_op_iterator(ValueAsMetadata **MultiIter) : I(MultiIter) {}
+
+ location_op_iterator(const location_op_iterator &R) : I(R.I) {}
+ location_op_iterator &operator=(const location_op_iterator &R) {
+ I = R.I;
+ return *this;
+ }
+ bool operator==(const location_op_iterator &RHS) const {
+ return I == RHS.I;
+ }
+ const Value *operator*() const {
+ ValueAsMetadata *VAM = I.is<ValueAsMetadata *>()
+ ? I.get<ValueAsMetadata *>()
+ : *I.get<ValueAsMetadata **>();
+ return VAM->getValue();
+ };
+ Value *operator*() {
+ ValueAsMetadata *VAM = I.is<ValueAsMetadata *>()
+ ? I.get<ValueAsMetadata *>()
+ : *I.get<ValueAsMetadata **>();
+ return VAM->getValue();
+ }
+ location_op_iterator &operator++() {
+ if (I.is<ValueAsMetadata *>())
+ I = I.get<ValueAsMetadata *>() + 1;
+ else
+ I = I.get<ValueAsMetadata **>() + 1;
+ return *this;
+ }
+ location_op_iterator &operator--() {
+ if (I.is<ValueAsMetadata *>())
+ I = I.get<ValueAsMetadata *>() - 1;
+ else
+ I = I.get<ValueAsMetadata **>() - 1;
+ return *this;
+ }
+ };
+
+ /// Get the locations corresponding to the variable referenced by the debug
+ /// info intrinsic. Depending on the intrinsic, this could be the
+ /// variable's value or its address.
+ iterator_range<location_op_iterator> location_ops() const;
+
+ Value *getVariableLocationOp(unsigned OpIdx) const;
+
+ void replaceVariableLocationOp(Value *OldValue, Value *NewValue,
+ bool AllowEmpty = false);
+ void replaceVariableLocationOp(unsigned OpIdx, Value *NewValue);
+ /// Adding a new location operand will always result in this intrinsic using
+ /// an ArgList, and must always be accompanied by a new expression that uses
+ /// the new operand.
+ void addVariableLocationOps(ArrayRef<Value *> NewValues,
+ DIExpression *NewExpr);
+
+ void setVariable(DILocalVariable *NewVar) { Variable = NewVar; }
+
+ void setExpression(DIExpression *NewExpr) { Expression = NewExpr; }
+
+ unsigned getNumVariableLocationOps() const {
+ if (hasArgList())
+ return cast<DIArgList>(getRawLocation())->getArgs().size();
+ return 1;
+ }
+
+ bool hasArgList() const { return isa<DIArgList>(getRawLocation()); }
+ /// Returns true if this DPValue has no empty MDNodes in its location list.
+ bool hasValidLocation() const { return getVariableLocationOp(0) != nullptr; }
+
+ /// Does this describe the address of a local variable. True for dbg.addr
+ /// and dbg.declare, but not dbg.value, which describes its value.
+ bool isAddressOfVariable() const { return Type != LocationType::Value; }
+ LocationType getType() const { return Type; }
+
+ DebugLoc getDebugLoc() const { return DbgLoc; }
+ void setDebugLoc(DebugLoc Loc) { DbgLoc = std::move(Loc); }
+
+ void setKillLocation() {
+ // TODO: When/if we remove duplicate values from DIArgLists, we don't need
+ // this set anymore.
+ SmallPtrSet<Value *, 4> RemovedValues;
+ for (Value *OldValue : location_ops()) {
+ if (!RemovedValues.insert(OldValue).second)
+ continue;
+ Value *Poison = PoisonValue::get(OldValue->getType());
+ replaceVariableLocationOp(OldValue, Poison);
+ }
+ }
+
+ bool isKillLocation() const {
+ return (getNumVariableLocationOps() == 0 &&
+ !getExpression()->isComplex()) ||
+ any_of(location_ops(), [](Value *V) { return isa<UndefValue>(V); });
+ }
+
+ DILocalVariable *getVariable() const { return Variable; }
+
+ DIExpression *getExpression() const { return Expression; }
+
+ Metadata *getRawLocation() const { return DebugValue; }
+
+ /// Use of this should generally be avoided; instead,
+ /// replaceVariableLocationOp and addVariableLocationOps should be used where
+ /// possible to avoid creating invalid state.
+ void setRawLocation(Metadata *NewLocation) {
+ assert(
+ (isa<ValueAsMetadata>(NewLocation) || isa<DIArgList>(NewLocation) ||
+ isa<MDNode>(NewLocation)) &&
+ "Location for a DPValue must be either ValueAsMetadata or DIArgList");
+ resetDebugValue(NewLocation);
+ }
+
+ /// Get the size (in bits) of the variable, or fragment of the variable that
+ /// is described.
+ std::optional<uint64_t> getFragmentSizeInBits() const;
+
+ DPValue *clone() const;
+ /// Convert this DPValue back into a dbg.value intrinsic.
+ /// \p InsertBefore Optional position to insert this intrinsic.
+ /// \returns A new dbg.value intrinsic representiung this DPValue.
+ DbgVariableIntrinsic *createDebugIntrinsic(Module *M,
+ Instruction *InsertBefore) const;
+ /// Handle changes to the location of the Value(s) that we refer to happening
+ /// "under our feet".
+ void handleChangedLocation(Metadata *NewLocation);
+
+ void setMarker(DPMarker *M) { Marker = M; }
+
+ DPMarker *getMarker() { return Marker; }
+ const DPMarker *getMarker() const { return Marker; }
+
+ BasicBlock *getBlock();
+ const BasicBlock *getBlock() const;
+
+ Function *getFunction();
+ const Function *getFunction() const;
+
+ Module *getModule();
+ const Module *getModule() const;
+
+ LLVMContext &getContext();
+ const LLVMContext &getContext() const;
+
+ void print(raw_ostream &O, bool IsForDebug = false) const;
+ void print(raw_ostream &ROS, ModuleSlotTracker &MST, bool IsForDebug) const;
+};
+
+/// Per-instruction record of debug-info. If an Instruction is the position of
+/// some debugging information, it points at a DPMarker storing that info. Each
+/// marker points back at the instruction that owns it. Various utilities are
+/// provided for manipulating the DPValues contained within this marker.
+///
+/// This class has a rough surface area, because it's needed to preserve the one
+/// arefact that we can't yet eliminate from the intrinsic / dbg.value
+/// debug-info design: the order of DPValues/records is significant, and
+/// duplicates can exist. Thus, if one has a run of debug-info records such as:
+/// dbg.value(...
+/// %foo = barinst
+/// dbg.value(...
+/// and remove barinst, then the dbg.values must be preserved in the correct
+/// order. Hence, the use of iterators to select positions to insert things
+/// into, or the occasional InsertAtHead parameter indicating that new records
+/// should go at the start of the list.
+///
+/// There are only five or six places in LLVM that truly rely on this ordering,
+/// which we can improve in the future. Additionally, many improvements in the
+/// way that debug-info is stored can be achieved in this class, at a future
+/// date.
+class DPMarker {
+public:
+ DPMarker() {}
+ /// Link back to the Instruction that owns this marker. Can be null during
+ /// operations that move a marker from one instruction to another.
+ Instruction *MarkedInstr = nullptr;
+
+ /// List of DPValues, each recording a single variable assignment, the
+ /// equivalent of a dbg.value intrinsic. There is a one-to-one relationship
+ /// between each dbg.value in a block and each DPValue once the
+ /// representation has been converted, and the ordering of DPValues is
+ /// meaningful in the same was a dbg.values.
+ simple_ilist<DPValue> StoredDPValues;
+
+ const BasicBlock *getParent() const;
+ BasicBlock *getParent();
+
+ /// Handle the removal of a marker: the position of debug-info has gone away,
+ /// but the stored debug records should not. Drop them onto the next
+ /// instruction, or otherwise work out what to do with them.
+ void removeMarker();
+ void dump() const;
+
+ void removeFromParent();
+ void eraseFromParent();
+
+ /// Implement operator<< on DPMarker.
+ void print(raw_ostream &O, bool IsForDebug = false) const;
+ void print(raw_ostream &ROS, ModuleSlotTracker &MST, bool IsForDebug) const;
+
+ /// Produce a range over all the DPValues in this Marker.
+ iterator_range<simple_ilist<DPValue>::iterator> getDbgValueRange();
+ /// Transfer any DPValues from \p Src into this DPMarker. If \p InsertAtHead
+ /// is true, place them before existing DPValues, otherwise afterwards.
+ void absorbDebugValues(DPMarker &Src, bool InsertAtHead);
+ /// Insert a DPValue into this DPMarker, at the end of the list. If
+ /// \p InsertAtHead is true, at the start.
+ void insertDPValue(DPValue *New, bool InsertAtHead);
+ /// Clone all DPMarkers from \p From into this marker. There are numerous
+ /// options to customise the source/destination, due to gnarliness, see class
+ /// comment.
+ /// \p FromHere If non-null, copy from FromHere to the end of From's DPValues
+ /// \p InsertAtHead Place the cloned DPValues at the start of StoredDPValues
+ /// \returns Range over all the newly cloned DPValues
+ iterator_range<simple_ilist<DPValue>::iterator>
+ cloneDebugInfoFrom(DPMarker *From,
+ std::optional<simple_ilist<DPValue>::iterator> FromHere,
+ bool InsertAtHead = false);
+ /// Erase all DPValues in this DPMarker.
+ void dropDPValues();
+ /// Erase a single DPValue from this marker. In an ideal future, we would
+ /// never erase an assignment in this way, but it's the equivalent to
+ /// erasing a dbg.value from a block.
+ void dropOneDPValue(DPValue *DPV);
+
+ /// We generally act like all llvm Instructions have a range of DPValues
+ /// attached to them, but in reality sometimes we don't allocate the DPMarker
+ /// to save time and memory, but still have to return ranges of DPValues. When
+ /// we need to describe such an unallocated DPValue range, use this static
+ /// markers range instead. This will bite us if someone tries to insert a
+ /// DPValue in that range, but they should be using the Official (TM) API for
+ /// that.
+ static DPMarker EmptyDPMarker;
+ static iterator_range<simple_ilist<DPValue>::iterator> getEmptyDPValueRange(){
+ return make_range(EmptyDPMarker.StoredDPValues.end(), EmptyDPMarker.StoredDPValues.end());
+ }
+};
+
+inline raw_ostream &operator<<(raw_ostream &OS, const DPMarker &Marker) {
+ Marker.print(OS);
+ return OS;
+}
+
+inline raw_ostream &operator<<(raw_ostream &OS, const DPValue &Value) {
+ Value.print(OS);
+ return OS;
+}
+
+} // namespace llvm
+
+#endif // LLVM_IR_DEBUGPROGRAMINSTRUCTION_H
diff --git a/llvm/include/llvm/IR/Function.h b/llvm/include/llvm/IR/Function.h
index 692ef75..1628aaf 100644
--- a/llvm/include/llvm/IR/Function.h
+++ b/llvm/include/llvm/IR/Function.h
@@ -97,15 +97,28 @@ private:
friend class SymbolTableListTraits<Function>;
+public:
+ /// Is this function using intrinsics to record the position of debugging
+ /// information, or non-intrinsic records? See IsNewDbgInfoFormat in
+ /// \ref BasicBlock.
+ bool IsNewDbgInfoFormat;
+
/// hasLazyArguments/CheckLazyArguments - The argument list of a function is
/// built on demand, so that the list isn't allocated until the first client
/// needs it. The hasLazyArguments predicate returns true if the arg list
/// hasn't been set up yet.
-public:
bool hasLazyArguments() const {
return getSubclassDataFromValue() & (1<<0);
}
+ /// \see BasicBlock::convertToNewDbgValues.
+ void convertToNewDbgValues();
+
+ /// \see BasicBlock::convertFromNewDbgValues.
+ void convertFromNewDbgValues();
+
+ void setIsNewDbgInfoFormat(bool NewVal);
+
private:
void CheckLazyArguments() const {
if (hasLazyArguments())
@@ -692,6 +705,7 @@ public:
/// Insert \p BB in the basic block list at \p Position. \Returns an iterator
/// to the newly inserted BB.
Function::iterator insert(Function::iterator Position, BasicBlock *BB) {
+ BB->setIsNewDbgInfoFormat(IsNewDbgInfoFormat);
return BasicBlocks.insert(Position, BB);
}
diff --git a/llvm/include/llvm/IR/Instruction.h b/llvm/include/llvm/IR/Instruction.h
index b5ccdf0..7f69421 100644
--- a/llvm/include/llvm/IR/Instruction.h
+++ b/llvm/include/llvm/IR/Instruction.h
@@ -29,10 +29,12 @@
namespace llvm {
class BasicBlock;
+class DPMarker;
class FastMathFlags;
class MDNode;
class Module;
struct AAMDNodes;
+class DPMarker;
template <> struct ilist_alloc_traits<Instruction> {
static inline void deleteNode(Instruction *V);
@@ -51,6 +53,12 @@ private:
/// O(1) local dominance checks between instructions.
mutable unsigned Order = 0;
+public:
+ /// Optional marker recording the position for debugging information that
+ /// takes effect immediately before this instruction. Null unless there is
+ /// debugging information present.
+ DPMarker *DbgMarker = nullptr;
+
protected:
// The 15 first bits of `Value::SubclassData` are available for subclasses of
// `Instruction` to use.
diff --git a/llvm/include/llvm/IR/Metadata.h b/llvm/include/llvm/IR/Metadata.h
index 9659dbe..a245dab 100644
--- a/llvm/include/llvm/IR/Metadata.h
+++ b/llvm/include/llvm/IR/Metadata.h
@@ -43,6 +43,7 @@ namespace llvm {
class Module;
class ModuleSlotTracker;
class raw_ostream;
+class DPValue;
template <typename T> class StringMapEntry;
template <typename ValueTy> class StringMapEntryStorage;
class Type;
@@ -201,6 +202,78 @@ private:
void untrack();
};
+/// Base class for tracking ValueAsMetadata/DIArgLists with user lookups and
+/// Owner callbacks outside of ValueAsMetadata.
+///
+/// Currently only inherited by DPValue; if other classes need to use it, then
+/// a SubclassID will need to be added (either as a new field or by making
+/// DebugValue into a PointerIntUnion) to discriminate between the subclasses in
+/// lookup and callback handling.
+class DebugValueUser {
+protected:
+ Metadata *DebugValue;
+
+public:
+ DPValue *getUser();
+ const DPValue *getUser() const;
+ void handleChangedValue(Metadata *NewDebugValue);
+ DebugValueUser() = default;
+ explicit DebugValueUser(Metadata *DebugValue) : DebugValue(DebugValue) {
+ trackDebugValue();
+ }
+
+ DebugValueUser(DebugValueUser &&X) : DebugValue(X.DebugValue) {
+ retrackDebugValue(X);
+ }
+ DebugValueUser(const DebugValueUser &X) : DebugValue(X.DebugValue) {
+ trackDebugValue();
+ }
+
+ DebugValueUser &operator=(DebugValueUser &&X) {
+ if (&X == this)
+ return *this;
+
+ untrackDebugValue();
+ DebugValue = X.DebugValue;
+ retrackDebugValue(X);
+ return *this;
+ }
+
+ DebugValueUser &operator=(const DebugValueUser &X) {
+ if (&X == this)
+ return *this;
+
+ untrackDebugValue();
+ DebugValue = X.DebugValue;
+ trackDebugValue();
+ return *this;
+ }
+
+ ~DebugValueUser() { untrackDebugValue(); }
+
+ void resetDebugValue() {
+ untrackDebugValue();
+ DebugValue = nullptr;
+ }
+ void resetDebugValue(Metadata *DebugValue) {
+ untrackDebugValue();
+ this->DebugValue = DebugValue;
+ trackDebugValue();
+ }
+
+ bool operator==(const DebugValueUser &X) const {
+ return DebugValue == X.DebugValue;
+ }
+ bool operator!=(const DebugValueUser &X) const {
+ return DebugValue != X.DebugValue;
+ }
+
+private:
+ void trackDebugValue();
+ void untrackDebugValue();
+ void retrackDebugValue(DebugValueUser &X);
+};
+
/// API for tracking metadata references through RAUW and deletion.
///
/// Shared API for updating \a Metadata pointers in subclasses that support
@@ -241,6 +314,15 @@ public:
return track(Ref, MD, &Owner);
}
+ /// Track the reference to metadata for \a DebugValueUser.
+ ///
+ /// As \a track(Metadata*&), but with support for calling back to \c Owner to
+ /// tell it that its operand changed. This could trigger \c Owner being
+ /// re-uniqued.
+ static bool track(void *Ref, Metadata &MD, DebugValueUser &Owner) {
+ return track(Ref, MD, &Owner);
+ }
+
/// Stop tracking a reference to metadata.
///
/// Stops \c *MD from tracking \c MD.
@@ -263,7 +345,7 @@ public:
/// Check whether metadata is replaceable.
static bool isReplaceable(const Metadata &MD);
- using OwnerTy = PointerUnion<MetadataAsValue *, Metadata *>;
+ using OwnerTy = PointerUnion<MetadataAsValue *, Metadata *, DebugValueUser *>;
private:
/// Track a reference to metadata for an owner.
@@ -275,8 +357,8 @@ private:
/// Shared implementation of use-lists for replaceable metadata.
///
/// Most metadata cannot be RAUW'ed. This is a shared implementation of
-/// use-lists and associated API for the two that support it (\a ValueAsMetadata
-/// and \a TempMDNode).
+/// use-lists and associated API for the three that support it (
+/// \a ValueAsMetadata, \a TempMDNode, and \a DIArgList).
class ReplaceableMetadataImpl {
friend class MetadataTracking;
@@ -305,6 +387,8 @@ public:
static void SalvageDebugInfo(const Constant &C);
/// Returns the list of all DIArgList users of this.
SmallVector<Metadata *> getAllArgListUsers();
+ /// Returns the list of all DPValue users of this.
+ SmallVector<DPValue *> getAllDPValueUsers();
/// Resolve all uses of this.
///
@@ -388,6 +472,9 @@ public:
SmallVector<Metadata *> getAllArgListUsers() {
return ReplaceableMetadataImpl::getAllArgListUsers();
}
+ SmallVector<DPValue *> getAllDPValueUsers() {
+ return ReplaceableMetadataImpl::getAllDPValueUsers();
+ }
static void handleDeletion(Value *V);
static void handleRAUW(Value *From, Value *To);
@@ -1133,11 +1220,15 @@ public:
bool isDistinct() const { return Storage == Distinct; }
bool isTemporary() const { return Storage == Temporary; }
+ bool isReplaceable() const {
+ return isTemporary() || getMetadataID() == DIArgListKind;
+ }
+
/// RAUW a temporary.
///
/// \pre \a isTemporary() must be \c true.
void replaceAllUsesWith(Metadata *MD) {
- assert(isTemporary() && "Expected temporary node");
+ assert(isReplaceable() && "Expected temporary/replaceable node");
if (Context.hasReplaceableUses())
Context.getReplaceableUses()->replaceAllUsesWith(MD);
}
diff --git a/llvm/include/llvm/IR/Module.h b/llvm/include/llvm/IR/Module.h
index 70beddd..68a89dc 100644
--- a/llvm/include/llvm/IR/Module.h
+++ b/llvm/include/llvm/IR/Module.h
@@ -213,6 +213,27 @@ private:
/// @name Constructors
/// @{
public:
+ /// Is this Module using intrinsics to record the position of debugging
+ /// information, or non-intrinsic records? See IsNewDbgInfoFormat in
+ /// \ref BasicBlock.
+ bool IsNewDbgInfoFormat;
+
+ /// \see BasicBlock::convertToNewDbgValues.
+ void convertToNewDbgValues() {
+ for (auto &F : *this) {
+ F.convertToNewDbgValues();
+ }
+ IsNewDbgInfoFormat = true;
+ }
+
+ /// \see BasicBlock::convertFromNewDbgValues.
+ void convertFromNewDbgValues() {
+ for (auto &F : *this) {
+ F.convertFromNewDbgValues();
+ }
+ IsNewDbgInfoFormat = false;
+ }
+
/// The Module constructor. Note that there is no default constructor. You
/// must provide a name for the module upon construction.
explicit Module(StringRef ModuleID, LLVMContext& C);
diff --git a/llvm/lib/IR/BasicBlock.cpp b/llvm/lib/IR/BasicBlock.cpp
index 46b1a3b..d238b65 100644
--- a/llvm/lib/IR/BasicBlock.cpp
+++ b/llvm/lib/IR/BasicBlock.cpp
@@ -16,16 +16,176 @@
#include "llvm/ADT/Statistic.h"
#include "llvm/IR/CFG.h"
#include "llvm/IR/Constants.h"
+#include "llvm/IR/DebugProgramInstruction.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Type.h"
+#include "llvm/Support/CommandLine.h"
+
+#include "LLVMContextImpl.h"
using namespace llvm;
#define DEBUG_TYPE "ir"
STATISTIC(NumInstrRenumberings, "Number of renumberings across all blocks");
+cl::opt<bool>
+ UseNewDbgInfoFormat("experimental-debuginfo-iterators",
+ cl::desc("Enable communicating debuginfo positions "
+ "through iterators, eliminating intrinsics"),
+ cl::init(false));
+
+DPMarker *BasicBlock::createMarker(Instruction *I) {
+ assert(IsNewDbgInfoFormat &&
+ "Tried to create a marker in a non new debug-info block!");
+ assert(I->DbgMarker == nullptr &&
+ "Tried to create marker for instuction that already has one!");
+ DPMarker *Marker = new DPMarker();
+ Marker->MarkedInstr = I;
+ I->DbgMarker = Marker;
+ return Marker;
+}
+
+DPMarker *BasicBlock::createMarker(InstListType::iterator It) {
+ assert(IsNewDbgInfoFormat &&
+ "Tried to create a marker in a non new debug-info block!");
+ if (It != end())
+ return createMarker(&*It);
+ DPMarker *DPM = getTrailingDPValues();
+ if (DPM)
+ return DPM;
+ DPM = new DPMarker();
+ setTrailingDPValues(DPM);
+ return DPM;
+}
+
+void BasicBlock::convertToNewDbgValues() {
+ // Is the command line option set?
+ if (!UseNewDbgInfoFormat)
+ return;
+
+ IsNewDbgInfoFormat = true;
+
+ // Iterate over all instructions in the instruction list, collecting dbg.value
+ // instructions and converting them to DPValues. Once we find a "real"
+ // instruction, attach all those DPValues to a DPMarker in that instruction.
+ SmallVector<DPValue *, 4> DPVals;
+ for (Instruction &I : make_early_inc_range(InstList)) {
+ assert(!I.DbgMarker && "DbgMarker already set on old-format instrs?");
+ if (DbgValueInst *DVI = dyn_cast<DbgValueInst>(&I)) {
+ // Convert this dbg.value to a DPValue.
+ DPValue *Value = new DPValue(DVI);
+ DPVals.push_back(Value);
+ DVI->eraseFromParent();
+ continue;
+ }
+
+ // Create a marker to store DPValues in. Technically we don't need to store
+ // one marker per instruction, but that's a future optimisation.
+ createMarker(&I);
+ DPMarker *Marker = I.DbgMarker;
+
+ for (DPValue *DPV : DPVals)
+ Marker->insertDPValue(DPV, false);
+
+ DPVals.clear();
+ }
+}
+
+void BasicBlock::convertFromNewDbgValues() {
+ invalidateOrders();
+ IsNewDbgInfoFormat = false;
+
+ // Iterate over the block, finding instructions annotated with DPMarkers.
+ // Convert any attached DPValues to dbg.values and insert ahead of the
+ // instruction.
+ for (auto &Inst : *this) {
+ if (!Inst.DbgMarker)
+ continue;
+
+ DPMarker &Marker = *Inst.DbgMarker;
+ for (DPValue &DPV : Marker.getDbgValueRange())
+ InstList.insert(Inst.getIterator(),
+ DPV.createDebugIntrinsic(getModule(), nullptr));
+
+ Marker.eraseFromParent();
+ };
+
+ // Assume no trailing DPValues: we could technically create them at the end
+ // of the block, after a terminator, but this would be non-cannonical and
+ // indicates that something else is broken somewhere.
+ assert(!getTrailingDPValues());
+}
+
+bool BasicBlock::validateDbgValues(bool Assert, bool Msg, raw_ostream *OS) {
+ bool RetVal = false;
+ if (!OS)
+ OS = &errs();
+
+ // Helper lambda for reporting failures: via assertion, printing, and return
+ // value.
+ auto TestFailure = [Assert, Msg, &RetVal, OS](bool Val, const char *Text) {
+ // Did the test fail?
+ if (Val)
+ return;
+
+ // If we're asserting, then fire off an assertion.
+ if (Assert)
+ llvm_unreachable(Text);
+
+ if (Msg)
+ *OS << Text << "\n";
+ RetVal = true;
+ };
+
+ // We should have the same debug-format as the parent function.
+ TestFailure(getParent()->IsNewDbgInfoFormat == IsNewDbgInfoFormat,
+ "Parent function doesn't have the same debug-info format");
+
+ // Only validate if we are using the new format.
+ if (!IsNewDbgInfoFormat)
+ return RetVal;
+
+ // Match every DPMarker to every Instruction and vice versa, and
+ // verify that there are no invalid DPValues.
+ for (auto It = begin(); It != end(); ++It) {
+ if (!It->DbgMarker)
+ continue;
+
+ // Validate DebugProgramMarkers.
+ DPMarker *CurrentDebugMarker = It->DbgMarker;
+
+ // If this is a marker, it should match the instruction and vice versa.
+ TestFailure(CurrentDebugMarker->MarkedInstr == &*It,
+ "Debug Marker points to incorrect instruction?");
+
+ // Now validate any DPValues in the marker.
+ for (DPValue &DPV : CurrentDebugMarker->getDbgValueRange()) {
+ // Validate DebugProgramValues.
+ TestFailure(DPV.getMarker() == CurrentDebugMarker,
+ "Not pointing at correct next marker!");
+
+ // Verify that no DbgValues appear prior to PHIs.
+ TestFailure(
+ !isa<PHINode>(It),
+ "DebugProgramValues must not appear before PHI nodes in a block!");
+ }
+ }
+
+ // Except transiently when removing + re-inserting the block terminator, there
+ // should be no trailing DPValues.
+ TestFailure(!getTrailingDPValues(), "Trailing DPValues in block");
+ return RetVal;
+}
+
+void BasicBlock::setIsNewDbgInfoFormat(bool NewFlag) {
+ if (NewFlag && !IsNewDbgInfoFormat)
+ convertToNewDbgValues();
+ else if (!NewFlag && IsNewDbgInfoFormat)
+ convertFromNewDbgValues();
+}
+
ValueSymbolTable *BasicBlock::getValueSymbolTable() {
if (Function *F = getParent())
return F->getValueSymbolTable();
@@ -47,7 +207,8 @@ template class llvm::SymbolTableListTraits<Instruction,
BasicBlock::BasicBlock(LLVMContext &C, const Twine &Name, Function *NewParent,
BasicBlock *InsertBefore)
- : Value(Type::getLabelTy(C), Value::BasicBlockVal), Parent(nullptr) {
+ : Value(Type::getLabelTy(C), Value::BasicBlockVal),
+ IsNewDbgInfoFormat(false), Parent(nullptr) {
if (NewParent)
insertInto(NewParent, InsertBefore);
@@ -56,12 +217,16 @@ BasicBlock::BasicBlock(LLVMContext &C, const Twine &Name, Function *NewParent,
"Cannot insert block before another block with no function!");
setName(Name);
+ if (NewParent)
+ setIsNewDbgInfoFormat(NewParent->IsNewDbgInfoFormat);
}
void BasicBlock::insertInto(Function *NewParent, BasicBlock *InsertBefore) {
assert(NewParent && "Expected a parent");
assert(!Parent && "Already has a parent");
+ setIsNewDbgInfoFormat(NewParent->IsNewDbgInfoFormat);
+
if (InsertBefore)
NewParent->insert(InsertBefore->getIterator(), this);
else
@@ -91,6 +256,11 @@ BasicBlock::~BasicBlock() {
assert(getParent() == nullptr && "BasicBlock still linked into the program!");
dropAllReferences();
+ for (auto &Inst : *this) {
+ if (!Inst.DbgMarker)
+ continue;
+ Inst.DbgMarker->eraseFromParent();
+ }
InstList.clear();
}
@@ -588,3 +758,16 @@ void BasicBlock::validateInstrOrdering() const {
}
}
#endif
+
+void BasicBlock::setTrailingDPValues(DPMarker *foo) {
+ getContext().pImpl->setTrailingDPValues(this, foo);
+}
+
+DPMarker *BasicBlock::getTrailingDPValues() {
+ return getContext().pImpl->getTrailingDPValues(this);
+}
+
+void BasicBlock::deleteTrailingDPValues() {
+ getContext().pImpl->deleteTrailingDPValues(this);
+}
+
diff --git a/llvm/lib/IR/CMakeLists.txt b/llvm/lib/IR/CMakeLists.txt
index d9656a2..5fe3d80 100644
--- a/llvm/lib/IR/CMakeLists.txt
+++ b/llvm/lib/IR/CMakeLists.txt
@@ -17,6 +17,7 @@ add_llvm_component_library(LLVMCore
DataLayout.cpp
DebugInfo.cpp
DebugInfoMetadata.cpp
+ DebugProgramInstruction.cpp
DebugLoc.cpp
DiagnosticHandler.cpp
DiagnosticInfo.cpp
diff --git a/llvm/lib/IR/DebugInfoMetadata.cpp b/llvm/lib/IR/DebugInfoMetadata.cpp
index f7f3612..48c4b62 100644
--- a/llvm/lib/IR/DebugInfoMetadata.cpp
+++ b/llvm/lib/IR/DebugInfoMetadata.cpp
@@ -2135,8 +2135,26 @@ void DIArgList::handleChangedOperand(void *Ref, Metadata *New) {
}
}
if (Uniq) {
+ // In the RemoveDIs project (eliminating debug-info-intrinsics), DIArgLists
+ // can be referred to by DebugValueUser objects, which necessitates them
+ // being unique and replaceable metadata. This causes a slight
+ // performance regression that's to be avoided during the early stages of
+ // the RemoveDIs prototype, see D154080.
+#ifdef EXPERIMENTAL_DEBUGINFO_ITERATORS
+ MDNode *UniqueArgList = uniquify();
+ if (UniqueArgList != this) {
+ replaceAllUsesWith(UniqueArgList);
+ // Clear this here so we don't try to untrack in the destructor.
+ Args.clear();
+ delete this;
+ return;
+ }
+#else
+ // Otherwise, don't fully unique, become distinct instead. See D108968,
+ // there's a latent bug that presents here as nondeterminism otherwise.
if (uniquify() != this)
storeDistinctInContext();
+#endif
}
track();
}
diff --git a/llvm/lib/IR/DebugProgramInstruction.cpp b/llvm/lib/IR/DebugProgramInstruction.cpp
new file mode 100644
index 0000000..3f39bae
--- /dev/null
+++ b/llvm/lib/IR/DebugProgramInstruction.cpp
@@ -0,0 +1,353 @@
+//======-- DebugProgramInstruction.cpp - Implement DPValues/DPMarkers --======//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/IR/DebugProgramInstruction.h"
+#include "llvm/IR/DIBuilder.h"
+#include "llvm/IR/IntrinsicInst.h"
+
+namespace llvm {
+
+DPValue::DPValue(const DbgVariableIntrinsic *DVI)
+ : DebugValueUser(DVI->getRawLocation()), Variable(DVI->getVariable()),
+ Expression(DVI->getExpression()), DbgLoc(DVI->getDebugLoc()) {
+ switch (DVI->getIntrinsicID()) {
+ case Intrinsic::dbg_value:
+ Type = LocationType::Value;
+ break;
+ case Intrinsic::dbg_declare:
+ Type = LocationType::Declare;
+ break;
+ default:
+ llvm_unreachable(
+ "Trying to create a DPValue with an invalid intrinsic type!");
+ }
+}
+
+DPValue::DPValue(const DPValue &DPV)
+ : DebugValueUser(DPV.getRawLocation()),
+ Variable(DPV.getVariable()), Expression(DPV.getExpression()),
+ DbgLoc(DPV.getDebugLoc()), Type(DPV.getType()) {}
+
+DPValue::DPValue(Metadata *Location, DILocalVariable *DV, DIExpression *Expr,
+ const DILocation *DI)
+ : DebugValueUser(Location), Variable(DV), Expression(Expr), DbgLoc(DI),
+ Type(LocationType::Value) {
+}
+
+void DPValue::deleteInstr() { delete this; }
+
+iterator_range<DPValue::location_op_iterator> DPValue::location_ops() const {
+ auto *MD = getRawLocation();
+ // If a Value has been deleted, the "location" for this DPValue will be
+ // replaced by nullptr. Return an empty range.
+ if (!MD)
+ return {location_op_iterator(static_cast<ValueAsMetadata *>(nullptr)),
+ location_op_iterator(static_cast<ValueAsMetadata *>(nullptr))};
+
+ // If operand is ValueAsMetadata, return a range over just that operand.
+ if (auto *VAM = dyn_cast<ValueAsMetadata>(MD))
+ return {location_op_iterator(VAM), location_op_iterator(VAM + 1)};
+
+ // If operand is DIArgList, return a range over its args.
+ if (auto *AL = dyn_cast<DIArgList>(MD))
+ return {location_op_iterator(AL->args_begin()),
+ location_op_iterator(AL->args_end())};
+
+ // Operand is an empty metadata tuple, so return empty iterator.
+ assert(cast<MDNode>(MD)->getNumOperands() == 0);
+ return {location_op_iterator(static_cast<ValueAsMetadata *>(nullptr)),
+ location_op_iterator(static_cast<ValueAsMetadata *>(nullptr))};
+}
+
+Value *DPValue::getVariableLocationOp(unsigned OpIdx) const {
+ auto *MD = getRawLocation();
+ if (!MD)
+ return nullptr;
+
+ if (auto *AL = dyn_cast<DIArgList>(MD))
+ return AL->getArgs()[OpIdx]->getValue();
+ if (isa<MDNode>(MD))
+ return nullptr;
+ assert(isa<ValueAsMetadata>(MD) &&
+ "Attempted to get location operand from DPValue with none.");
+ auto *V = cast<ValueAsMetadata>(MD);
+ assert(OpIdx == 0 && "Operand Index must be 0 for a debug intrinsic with a "
+ "single location operand.");
+ return V->getValue();
+}
+
+static ValueAsMetadata *getAsMetadata(Value *V) {
+ return isa<MetadataAsValue>(V) ? dyn_cast<ValueAsMetadata>(
+ cast<MetadataAsValue>(V)->getMetadata())
+ : ValueAsMetadata::get(V);
+}
+
+void DPValue::replaceVariableLocationOp(Value *OldValue, Value *NewValue,
+ bool AllowEmpty) {
+ assert(NewValue && "Values must be non-null");
+ auto Locations = location_ops();
+ auto OldIt = find(Locations, OldValue);
+ if (OldIt == Locations.end()) {
+ if (AllowEmpty)
+ return;
+ llvm_unreachable("OldValue must be a current location");
+ }
+
+ if (!hasArgList()) {
+ // Set our location to be the MAV wrapping the new Value.
+ setRawLocation(isa<MetadataAsValue>(NewValue)
+ ? cast<MetadataAsValue>(NewValue)->getMetadata()
+ : ValueAsMetadata::get(NewValue));
+ return;
+ }
+
+ // We must be referring to a DIArgList, produce a new operands vector with the
+ // old value replaced, generate a new DIArgList and set it as our location.
+ SmallVector<ValueAsMetadata *, 4> MDs;
+ ValueAsMetadata *NewOperand = getAsMetadata(NewValue);
+ for (auto *VMD : Locations)
+ MDs.push_back(VMD == *OldIt ? NewOperand : getAsMetadata(VMD));
+ setRawLocation(DIArgList::get(getVariableLocationOp(0)->getContext(), MDs));
+}
+
+void DPValue::replaceVariableLocationOp(unsigned OpIdx, Value *NewValue) {
+ assert(OpIdx < getNumVariableLocationOps() && "Invalid Operand Index");
+
+ if (!hasArgList()) {
+ setRawLocation(isa<MetadataAsValue>(NewValue)
+ ? cast<MetadataAsValue>(NewValue)->getMetadata()
+ : ValueAsMetadata::get(NewValue));
+ return;
+ }
+
+ SmallVector<ValueAsMetadata *, 4> MDs;
+ ValueAsMetadata *NewOperand = getAsMetadata(NewValue);
+ for (unsigned Idx = 0; Idx < getNumVariableLocationOps(); ++Idx)
+ MDs.push_back(Idx == OpIdx ? NewOperand
+ : getAsMetadata(getVariableLocationOp(Idx)));
+
+ setRawLocation(DIArgList::get(getVariableLocationOp(0)->getContext(), MDs));
+}
+
+void DPValue::addVariableLocationOps(ArrayRef<Value *> NewValues,
+ DIExpression *NewExpr) {
+ assert(NewExpr->hasAllLocationOps(getNumVariableLocationOps() +
+ NewValues.size()) &&
+ "NewExpr for debug variable intrinsic does not reference every "
+ "location operand.");
+ assert(!is_contained(NewValues, nullptr) && "New values must be non-null");
+ setExpression(NewExpr);
+ SmallVector<ValueAsMetadata *, 4> MDs;
+ for (auto *VMD : location_ops())
+ MDs.push_back(getAsMetadata(VMD));
+ for (auto *VMD : NewValues)
+ MDs.push_back(getAsMetadata(VMD));
+ setRawLocation(DIArgList::get(getVariableLocationOp(0)->getContext(), MDs));
+}
+
+std::optional<uint64_t> DPValue::getFragmentSizeInBits() const {
+ if (auto Fragment = getExpression()->getFragmentInfo())
+ return Fragment->SizeInBits;
+ return getVariable()->getSizeInBits();
+}
+
+DPValue *DPValue::clone() const { return new DPValue(*this); }
+
+DbgVariableIntrinsic *
+DPValue::createDebugIntrinsic(Module *M, Instruction *InsertBefore) const {
+ [[maybe_unused]] DICompileUnit *Unit =
+ getDebugLoc().get()->getScope()->getSubprogram()->getUnit();
+ assert(M && Unit &&
+ "Cannot clone from BasicBlock that is not part of a Module or "
+ "DICompileUnit!");
+ LLVMContext &Context = getDebugLoc()->getContext();
+ Value *Args[] = {MetadataAsValue::get(Context, getRawLocation()),
+ MetadataAsValue::get(Context, getVariable()),
+ MetadataAsValue::get(Context, getExpression())};
+ Function *IntrinsicFn;
+
+ // Work out what sort of intrinsic we're going to produce.
+ switch (getType()) {
+ case DPValue::LocationType::Declare:
+ IntrinsicFn = Intrinsic::getDeclaration(M, Intrinsic::dbg_declare);
+ break;
+ case DPValue::LocationType::Value:
+ IntrinsicFn = Intrinsic::getDeclaration(M, Intrinsic::dbg_value);
+ break;
+ }
+
+ // Create the intrinsic from this DPValue's information, optionally insert
+ // into the target location.
+ DbgVariableIntrinsic *DVI = cast<DbgVariableIntrinsic>(
+ CallInst::Create(IntrinsicFn->getFunctionType(), IntrinsicFn, Args));
+ DVI->setTailCall();
+ DVI->setDebugLoc(getDebugLoc());
+ if (InsertBefore)
+ DVI->insertBefore(InsertBefore);
+
+ return DVI;
+}
+
+void DPValue::handleChangedLocation(Metadata *NewLocation) {
+ resetDebugValue(NewLocation);
+}
+
+const BasicBlock *DPValue::getParent() const {
+ return Marker->MarkedInstr->getParent();
+}
+
+BasicBlock *DPValue::getParent() { return Marker->MarkedInstr->getParent(); }
+
+BasicBlock *DPValue::getBlock() { return Marker->getParent(); }
+
+const BasicBlock *DPValue::getBlock() const { return Marker->getParent(); }
+
+Function *DPValue::getFunction() { return getBlock()->getParent(); }
+
+const Function *DPValue::getFunction() const { return getBlock()->getParent(); }
+
+Module *DPValue::getModule() { return getFunction()->getParent(); }
+
+const Module *DPValue::getModule() const { return getFunction()->getParent(); }
+
+LLVMContext &DPValue::getContext() { return getBlock()->getContext(); }
+
+const LLVMContext &DPValue::getContext() const {
+ return getBlock()->getContext();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+// An empty, global, DPMarker for the purpose of describing empty ranges of
+// DPValues.
+DPMarker DPMarker::EmptyDPMarker;
+
+void DPMarker::dropDPValues() {
+ while (!StoredDPValues.empty()) {
+ auto It = StoredDPValues.begin();
+ DPValue *DPV = &*It;
+ StoredDPValues.erase(It);
+ DPV->deleteInstr();
+ }
+}
+
+void DPMarker::dropOneDPValue(DPValue *DPV) {
+ assert(DPV->getMarker() == this);
+ StoredDPValues.erase(DPV->getIterator());
+ DPV->deleteInstr();
+}
+
+const BasicBlock *DPMarker::getParent() const {
+ return MarkedInstr->getParent();
+}
+
+BasicBlock *DPMarker::getParent() { return MarkedInstr->getParent(); }
+
+void DPMarker::removeMarker() {
+ // Are there any DPValues in this DPMarker? If not, nothing to preserve.
+ Instruction *Owner = MarkedInstr;
+ if (StoredDPValues.empty()) {
+ eraseFromParent();
+ Owner->DbgMarker = nullptr;
+ return;
+ }
+
+ // The attached DPValues need to be preserved; attach them to the next
+ // instruction. If there isn't a next instruction, put them on the
+ // "trailing" list.
+ // (This logic gets refactored in a future patch, needed to break some
+ // dependencies here).
+ BasicBlock::iterator NextInst = std::next(Owner->getIterator());
+ DPMarker *NextMarker;
+ if (NextInst == Owner->getParent()->end()) {
+ NextMarker = new DPMarker();
+ Owner->getParent()->setTrailingDPValues(NextMarker);
+ } else {
+ NextMarker = NextInst->DbgMarker;
+ }
+ NextMarker->absorbDebugValues(*this, true);
+
+ eraseFromParent();
+}
+
+void DPMarker::removeFromParent() {
+ MarkedInstr->DbgMarker = nullptr;
+ MarkedInstr = nullptr;
+}
+
+void DPMarker::eraseFromParent() {
+ if (MarkedInstr)
+ removeFromParent();
+ dropDPValues();
+ delete this;
+}
+
+iterator_range<DPValue::self_iterator> DPMarker::getDbgValueRange() {
+ return make_range(StoredDPValues.begin(), StoredDPValues.end());
+}
+
+void DPValue::removeFromParent() {
+ getMarker()->StoredDPValues.erase(getIterator());
+}
+
+void DPValue::eraseFromParent() {
+ removeFromParent();
+ deleteInstr();
+}
+
+void DPMarker::insertDPValue(DPValue *New, bool InsertAtHead) {
+ auto It = InsertAtHead ? StoredDPValues.begin() : StoredDPValues.end();
+ StoredDPValues.insert(It, *New);
+ New->setMarker(this);
+}
+
+void DPMarker::absorbDebugValues(DPMarker &Src, bool InsertAtHead) {
+ auto It = InsertAtHead ? StoredDPValues.begin() : StoredDPValues.end();
+ for (DPValue &DPV : Src.StoredDPValues)
+ DPV.setMarker(this);
+
+ StoredDPValues.splice(It, Src.StoredDPValues);
+}
+
+iterator_range<simple_ilist<DPValue>::iterator> DPMarker::cloneDebugInfoFrom(
+ DPMarker *From, std::optional<simple_ilist<DPValue>::iterator> from_here,
+ bool InsertAtHead) {
+ DPValue *First = nullptr;
+ // Work out what range of DPValues to clone: normally all the contents of the
+ // "From" marker, optionally we can start from the from_here position down to
+ // end().
+ auto Range =
+ make_range(From->StoredDPValues.begin(), From->StoredDPValues.end());
+ if (from_here.has_value())
+ Range = make_range(*from_here, From->StoredDPValues.end());
+
+ // Clone each DPValue and insert into StoreDPValues; optionally place them at
+ // the start or the end of the list.
+ auto Pos = (InsertAtHead) ? StoredDPValues.begin() : StoredDPValues.end();
+ for (DPValue &DPV : Range) {
+ DPValue *New = DPV.clone();
+ New->setMarker(this);
+ StoredDPValues.insert(Pos, *New);
+ if (!First)
+ First = New;
+ }
+
+ if (!First)
+ return {StoredDPValues.end(), StoredDPValues.end()};
+
+ if (InsertAtHead)
+ // If InsertAtHead is set, we cloned a range onto the front of of the
+ // StoredDPValues collection, return that range.
+ return {StoredDPValues.begin(), Pos};
+ else
+ // We inserted a block at the end, return that range.
+ return {First->getIterator(), StoredDPValues.end()};
+}
+
+} // end namespace llvm
+
diff --git a/llvm/lib/IR/Function.cpp b/llvm/lib/IR/Function.cpp
index 658aa67..49e0c1c 100644
--- a/llvm/lib/IR/Function.cpp
+++ b/llvm/lib/IR/Function.cpp
@@ -81,6 +81,27 @@ static cl::opt<unsigned> NonGlobalValueMaxNameSize(
"non-global-value-max-name-size", cl::Hidden, cl::init(1024),
cl::desc("Maximum size for the name of non-global values."));
+void Function::convertToNewDbgValues() {
+ IsNewDbgInfoFormat = true;
+ for (auto &BB : *this) {
+ BB.convertToNewDbgValues();
+ }
+}
+
+void Function::convertFromNewDbgValues() {
+ IsNewDbgInfoFormat = false;
+ for (auto &BB : *this) {
+ BB.convertFromNewDbgValues();
+ }
+}
+
+void Function::setIsNewDbgInfoFormat(bool NewFlag) {
+ if (NewFlag && !IsNewDbgInfoFormat)
+ convertToNewDbgValues();
+ else if (!NewFlag && IsNewDbgInfoFormat)
+ convertFromNewDbgValues();
+}
+
//===----------------------------------------------------------------------===//
// Argument Implementation
//===----------------------------------------------------------------------===//
@@ -402,7 +423,7 @@ Function::Function(FunctionType *Ty, LinkageTypes Linkage, unsigned AddrSpace,
: GlobalObject(Ty, Value::FunctionVal,
OperandTraits<Function>::op_begin(this), 0, Linkage, name,
computeAddrSpace(AddrSpace, ParentModule)),
- NumArgs(Ty->getNumParams()) {
+ NumArgs(Ty->getNumParams()), IsNewDbgInfoFormat(false) {
assert(FunctionType::isValidReturnType(getReturnType()) &&
"invalid return type");
setGlobalObjectSubClassData(0);
diff --git a/llvm/lib/IR/LLVMContextImpl.cpp b/llvm/lib/IR/LLVMContextImpl.cpp
index 2076eee..406850b 100644
--- a/llvm/lib/IR/LLVMContextImpl.cpp
+++ b/llvm/lib/IR/LLVMContextImpl.cpp
@@ -45,6 +45,14 @@ LLVMContextImpl::LLVMContextImpl(LLVMContext &C)
Int16Ty(C, 16), Int32Ty(C, 32), Int64Ty(C, 64), Int128Ty(C, 128) {}
LLVMContextImpl::~LLVMContextImpl() {
+#ifndef NDEBUG
+ // Check that any variable location records that fell off the end of a block
+ // when it's terminator was removed were eventually replaced. This assertion
+ // firing indicates that DPValues went missing during the lifetime of the
+ // LLVMContext.
+ assert(TrailingDPValues.empty() && "DPValue records in blocks not cleaned");
+#endif
+
// NOTE: We need to delete the contents of OwnedModules, but Module's dtor
// will call LLVMContextImpl::removeModule, thus invalidating iterators into
// the container. Avoid iterators during this operation:
diff --git a/llvm/lib/IR/LLVMContextImpl.h b/llvm/lib/IR/LLVMContextImpl.h
index 4cc3f8d..ebc444f 100644
--- a/llvm/lib/IR/LLVMContextImpl.h
+++ b/llvm/lib/IR/LLVMContextImpl.h
@@ -57,6 +57,7 @@ class AttributeListImpl;
class AttributeSetNode;
class BasicBlock;
struct DiagnosticHandler;
+class DPMarker;
class ElementCount;
class Function;
class GlobalObject;
@@ -1633,6 +1634,36 @@ public:
/// The lifetime of the object must be guaranteed to extend as long as the
/// LLVMContext is used by compilation.
void setOptPassGate(OptPassGate &);
+
+ /// Mapping of blocks to collections of "trailing" DPValues. As part of the
+ /// "RemoveDIs" project, debug-info variable location records are going to
+ /// cease being instructions... which raises the problem of where should they
+ /// be recorded when we remove the terminator of a blocks, such as:
+ ///
+ /// %foo = add i32 0, 0
+ /// br label %bar
+ ///
+ /// If the branch is removed, a legitimate transient state while editing a
+ /// block, any debug-records between those two instructions will not have a
+ /// location. Each block thus records any DPValue records that "trail" in
+ /// such a way. These are stored in LLVMContext because typically LLVM only
+ /// edits a small number of blocks at a time, so there's no need to bloat
+ /// BasicBlock with such a data structure.
+ SmallDenseMap<BasicBlock *, DPMarker *> TrailingDPValues;
+
+ // Set, get and delete operations for TrailingDPValues.
+ void setTrailingDPValues(BasicBlock *B, DPMarker *M) {
+ assert(!TrailingDPValues.count(B));
+ TrailingDPValues[B] = M;
+ }
+
+ DPMarker *getTrailingDPValues(BasicBlock *B) {
+ return TrailingDPValues.lookup(B);
+ }
+
+ void deleteTrailingDPValues(BasicBlock *B) {
+ TrailingDPValues.erase(B);
+ }
};
} // end namespace llvm
diff --git a/llvm/lib/IR/Metadata.cpp b/llvm/lib/IR/Metadata.cpp
index 7860280..61504e0 100644
--- a/llvm/lib/IR/Metadata.cpp
+++ b/llvm/lib/IR/Metadata.cpp
@@ -32,6 +32,7 @@
#include "llvm/IR/Constants.h"
#include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/IR/DebugLoc.h"
+#include "llvm/IR/DebugProgramInstruction.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GlobalObject.h"
#include "llvm/IR/GlobalVariable.h"
@@ -147,6 +148,32 @@ void MetadataAsValue::untrack() {
MetadataTracking::untrack(MD);
}
+DPValue *DebugValueUser::getUser() { return static_cast<DPValue *>(this); }
+const DPValue *DebugValueUser::getUser() const {
+ return static_cast<const DPValue *>(this);
+}
+void DebugValueUser::handleChangedValue(Metadata *NewMD) {
+ getUser()->handleChangedLocation(NewMD);
+}
+
+void DebugValueUser::trackDebugValue() {
+ if (DebugValue)
+ MetadataTracking::track(&DebugValue, *DebugValue, *this);
+}
+
+void DebugValueUser::untrackDebugValue() {
+ if (DebugValue)
+ MetadataTracking::untrack(DebugValue);
+}
+
+void DebugValueUser::retrackDebugValue(DebugValueUser &X) {
+ assert(DebugValue == X.DebugValue && "Expected values to match");
+ if (X.DebugValue) {
+ MetadataTracking::retrack(X.DebugValue, DebugValue);
+ X.DebugValue = nullptr;
+ }
+}
+
bool MetadataTracking::track(void *Ref, Metadata &MD, OwnerTy Owner) {
assert(Ref && "Expected live reference");
assert((Owner || *static_cast<Metadata **>(Ref) == &MD) &&
@@ -195,6 +222,8 @@ SmallVector<Metadata *> ReplaceableMetadataImpl::getAllArgListUsers() {
SmallVector<std::pair<OwnerTy, uint64_t> *> MDUsersWithID;
for (auto Pair : UseMap) {
OwnerTy Owner = Pair.second.first;
+ if (Owner.isNull())
+ continue;
if (!isa<Metadata *>(Owner))
continue;
Metadata *OwnerMD = cast<Metadata *>(Owner);
@@ -210,6 +239,25 @@ SmallVector<Metadata *> ReplaceableMetadataImpl::getAllArgListUsers() {
return MDUsers;
}
+SmallVector<DPValue *> ReplaceableMetadataImpl::getAllDPValueUsers() {
+ SmallVector<std::pair<OwnerTy, uint64_t> *> DPVUsersWithID;
+ for (auto Pair : UseMap) {
+ OwnerTy Owner = Pair.second.first;
+ if (Owner.isNull())
+ continue;
+ if (!Owner.is<DebugValueUser *>())
+ continue;
+ DPVUsersWithID.push_back(&UseMap[Pair.first]);
+ }
+ llvm::sort(DPVUsersWithID, [](auto UserA, auto UserB) {
+ return UserA->second < UserB->second;
+ });
+ SmallVector<DPValue *> DPVUsers;
+ for (auto UserWithID : DPVUsersWithID)
+ DPVUsers.push_back(UserWithID->first.get<DebugValueUser *>()->getUser());
+ return DPVUsers;
+}
+
void ReplaceableMetadataImpl::addRef(void *Ref, OwnerTy Owner) {
bool WasInserted =
UseMap.insert(std::make_pair(Ref, std::make_pair(Owner, NextIndex)))
@@ -308,6 +356,11 @@ void ReplaceableMetadataImpl::replaceAllUsesWith(Metadata *MD) {
continue;
}
+ if (Owner.is<DebugValueUser *>()) {
+ Owner.get<DebugValueUser *>()->getUser()->handleChangedLocation(MD);
+ continue;
+ }
+
// There's a Metadata owner -- dispatch.
Metadata *OwnerMD = cast<Metadata *>(Owner);
switch (OwnerMD->getMetadataID()) {
@@ -343,7 +396,7 @@ void ReplaceableMetadataImpl::resolveAllUses(bool ResolveUsers) {
auto Owner = Pair.second.first;
if (!Owner)
continue;
- if (isa<MetadataAsValue *>(Owner))
+ if (!Owner.is<Metadata *>())
continue;
// Resolve MDNodes that point at this.
@@ -356,19 +409,34 @@ void ReplaceableMetadataImpl::resolveAllUses(bool ResolveUsers) {
}
}
+// Special handing of DIArgList is required in the RemoveDIs project, see
+// commentry in DIArgList::handleChangedOperand for details. Hidden behind
+// conditional compilation to avoid a compile time regression.
ReplaceableMetadataImpl *ReplaceableMetadataImpl::getOrCreate(Metadata &MD) {
+#ifdef EXPERIMENTAL_DEBUGINFO_ITERATORS
+ if (auto *ArgList = dyn_cast<DIArgList>(&MD))
+ return ArgList->Context.getOrCreateReplaceableUses();
+#endif
if (auto *N = dyn_cast<MDNode>(&MD))
return N->isResolved() ? nullptr : N->Context.getOrCreateReplaceableUses();
return dyn_cast<ValueAsMetadata>(&MD);
}
ReplaceableMetadataImpl *ReplaceableMetadataImpl::getIfExists(Metadata &MD) {
+#ifdef EXPERIMENTAL_DEBUGINFO_ITERATORS
+ if (auto *ArgList = dyn_cast<DIArgList>(&MD))
+ return ArgList->Context.getReplaceableUses();
+#endif
if (auto *N = dyn_cast<MDNode>(&MD))
return N->isResolved() ? nullptr : N->Context.getReplaceableUses();
return dyn_cast<ValueAsMetadata>(&MD);
}
bool ReplaceableMetadataImpl::isReplaceable(const Metadata &MD) {
+#ifdef EXPERIMENTAL_DEBUGINFO_ITERATORS
+ if (isa<DIArgList>(&MD))
+ return true;
+#endif
if (auto *N = dyn_cast<MDNode>(&MD))
return !N->isResolved();
return isa<ValueAsMetadata>(&MD);
diff --git a/llvm/lib/IR/Module.cpp b/llvm/lib/IR/Module.cpp
index dba660b..17efe79 100644
--- a/llvm/lib/IR/Module.cpp
+++ b/llvm/lib/IR/Module.cpp
@@ -71,7 +71,8 @@ template class llvm::SymbolTableListTraits<GlobalIFunc>;
Module::Module(StringRef MID, LLVMContext &C)
: Context(C), ValSymTab(std::make_unique<ValueSymbolTable>(-1)),
- ModuleID(std::string(MID)), SourceFileName(std::string(MID)), DL("") {
+ ModuleID(std::string(MID)), SourceFileName(std::string(MID)), DL(""),
+ IsNewDbgInfoFormat(false) {
Context.addModule(this);
}
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index 1fa6bc1..b1d1075 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -2945,6 +2945,14 @@ void Verifier::visitBasicBlock(BasicBlock &BB) {
{
Check(I.getParent() == &BB, "Instruction has bogus parent pointer!");
}
+
+ // Confirm that no issues arise from the debug program.
+ if (BB.IsNewDbgInfoFormat) {
+ // Configure the validate function to not fire assertions, instead print
+ // errors and return true if there's a problem.
+ bool RetVal = BB.validateDbgValues(false, true, OS);
+ Check(!RetVal, "Invalid configuration of new-debug-info data found");
+ }
}
void Verifier::visitTerminator(Instruction &I) {
diff --git a/llvm/lib/Linker/IRMover.cpp b/llvm/lib/Linker/IRMover.cpp
index 2d45d85..e335def 100644
--- a/llvm/lib/Linker/IRMover.cpp
+++ b/llvm/lib/Linker/IRMover.cpp
@@ -1135,6 +1135,7 @@ Error IRLinker::linkFunctionBody(Function &Dst, Function &Src) {
Dst.setPrologueData(Src.getPrologueData());
if (Src.hasPersonalityFn())
Dst.setPersonalityFn(Src.getPersonalityFn());
+ assert(Src.IsNewDbgInfoFormat == Dst.IsNewDbgInfoFormat);
// Copy over the metadata attachments without remapping.
Dst.copyMetadata(&Src, 0);
@@ -1545,6 +1546,8 @@ Error IRLinker::run() {
if (Error Err = SrcM->getMaterializer()->materializeMetadata())
return Err;
+ DstM.IsNewDbgInfoFormat = SrcM->IsNewDbgInfoFormat;
+
// Inherit the target data from the source module if the destination module
// doesn't have one already.
if (DstM.getDataLayout().isDefault())
diff --git a/llvm/lib/Target/AMDGPU/AMDGPURewriteOutArguments.cpp b/llvm/lib/Target/AMDGPU/AMDGPURewriteOutArguments.cpp
index 2fde7af..e2055db 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPURewriteOutArguments.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPURewriteOutArguments.cpp
@@ -331,6 +331,8 @@ bool AMDGPURewriteOutArguments::runOnFunction(Function &F) {
NewFunc->removeRetAttrs(RetAttrs);
// TODO: How to preserve metadata?
+ NewFunc->setIsNewDbgInfoFormat(F.IsNewDbgInfoFormat);
+
// Move the body of the function into the new rewritten function, and replace
// this function with a stub.
NewFunc->splice(NewFunc->begin(), &F);
diff --git a/llvm/lib/Transforms/IPO/ArgumentPromotion.cpp b/llvm/lib/Transforms/IPO/ArgumentPromotion.cpp
index db9d5bc..fb3fa8d 100644
--- a/llvm/lib/Transforms/IPO/ArgumentPromotion.cpp
+++ b/llvm/lib/Transforms/IPO/ArgumentPromotion.cpp
@@ -161,6 +161,7 @@ doPromotion(Function *F, FunctionAnalysisManager &FAM,
F->getName());
NF->copyAttributesFrom(F);
NF->copyMetadata(F, 0);
+ NF->setIsNewDbgInfoFormat(F->IsNewDbgInfoFormat);
// The new function will have the !dbg metadata copied from the original
// function. The original function may not be deleted, and dbg metadata need
diff --git a/llvm/lib/Transforms/IPO/DeadArgumentElimination.cpp b/llvm/lib/Transforms/IPO/DeadArgumentElimination.cpp
index 24c0923..4f65748 100644
--- a/llvm/lib/Transforms/IPO/DeadArgumentElimination.cpp
+++ b/llvm/lib/Transforms/IPO/DeadArgumentElimination.cpp
@@ -174,6 +174,7 @@ bool DeadArgumentEliminationPass::deleteDeadVarargs(Function &F) {
NF->setComdat(F.getComdat());
F.getParent()->getFunctionList().insert(F.getIterator(), NF);
NF->takeName(&F);
+ NF->IsNewDbgInfoFormat = F.IsNewDbgInfoFormat;
// Loop over all the callers of the function, transforming the call sites
// to pass in a smaller number of arguments into the new function.
@@ -877,6 +878,7 @@ bool DeadArgumentEliminationPass::removeDeadStuffFromFunction(Function *F) {
// it again.
F->getParent()->getFunctionList().insert(F->getIterator(), NF);
NF->takeName(F);
+ NF->IsNewDbgInfoFormat = F->IsNewDbgInfoFormat;
// Loop over all the callers of the function, transforming the call sites to
// pass in a smaller number of arguments into the new function.
diff --git a/llvm/lib/Transforms/Utils/CloneFunction.cpp b/llvm/lib/Transforms/Utils/CloneFunction.cpp
index d552086..94c6abc 100644
--- a/llvm/lib/Transforms/Utils/CloneFunction.cpp
+++ b/llvm/lib/Transforms/Utils/CloneFunction.cpp
@@ -44,6 +44,7 @@ BasicBlock *llvm::CloneBasicBlock(const BasicBlock *BB, ValueToValueMapTy &VMap,
ClonedCodeInfo *CodeInfo,
DebugInfoFinder *DIFinder) {
BasicBlock *NewBB = BasicBlock::Create(BB->getContext(), "", F);
+ NewBB->IsNewDbgInfoFormat = BB->IsNewDbgInfoFormat;
if (BB->hasName())
NewBB->setName(BB->getName() + NameSuffix);
@@ -472,6 +473,7 @@ void PruningFunctionCloner::CloneBlock(
BasicBlock *NewBB;
Twine NewName(BB->hasName() ? Twine(BB->getName()) + NameSuffix : "");
BBEntry = NewBB = BasicBlock::Create(BB->getContext(), NewName, NewFunc);
+ NewBB->IsNewDbgInfoFormat = BB->IsNewDbgInfoFormat;
// It is only legal to clone a function if a block address within that
// function is never referenced outside of the function. Given that, we
diff --git a/llvm/unittests/IR/DebugInfoTest.cpp b/llvm/unittests/IR/DebugInfoTest.cpp
index 84ed733..034a923 100644
--- a/llvm/unittests/IR/DebugInfoTest.cpp
+++ b/llvm/unittests/IR/DebugInfoTest.cpp
@@ -11,6 +11,7 @@
#include "llvm/AsmParser/Parser.h"
#include "llvm/IR/DIBuilder.h"
#include "llvm/IR/DebugInfoMetadata.h"
+#include "llvm/IR/DebugProgramInstruction.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/LLVMContext.h"
@@ -23,6 +24,8 @@
using namespace llvm;
+extern cl::opt<bool> UseNewDbgInfoFormat;
+
static std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) {
SMDiagnostic Err;
std::unique_ptr<Module> Mod = parseAssemblyString(IR, Err, C);
@@ -743,4 +746,310 @@ TEST(AssignmentTrackingTest, InstrMethods) {
}
}
+// Test some very straight-forward operations on DPValues -- these are
+// dbg.values that have been converted to a non-instruction format.
+TEST(MetadataTest, ConvertDbgToDPValue) {
+ LLVMContext C;
+ std::unique_ptr<Module> M = parseIR(C, R"(
+ define i16 @f(i16 %a) !dbg !6 {
+ call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata !DIExpression()), !dbg !11
+ %b = add i16 %a, 1, !dbg !11
+ call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), !dbg !11
+ ret i16 0, !dbg !11
+
+ exit:
+ %c = add i16 %b, 1, !dbg !11
+ ret i16 0, !dbg !11
+ }
+ declare void @llvm.dbg.value(metadata, metadata, metadata) #0
+ attributes #0 = { nounwind readnone speculatable willreturn }
+
+ !llvm.dbg.cu = !{!0}
+ !llvm.module.flags = !{!5}
+
+ !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
+ !1 = !DIFile(filename: "t.ll", directory: "/")
+ !2 = !{}
+ !5 = !{i32 2, !"Debug Info Version", i32 3}
+ !6 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)
+ !7 = !DISubroutineType(types: !2)
+ !8 = !{!9}
+ !9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10)
+ !10 = !DIBasicType(name: "ty16", size: 16, encoding: DW_ATE_unsigned)
+ !11 = !DILocation(line: 1, column: 1, scope: !6)
+)");
+
+ // Find the first dbg.value,
+ Instruction &I = *M->getFunction("f")->getEntryBlock().getFirstNonPHI();
+ const DILocalVariable *Var = nullptr;
+ const DIExpression *Expr = nullptr;
+ const DILocation *Loc = nullptr;
+ const Metadata *MLoc = nullptr;
+ DPValue *DPV1 = nullptr;
+ {
+ DbgValueInst *DPI = dyn_cast<DbgValueInst>(&I);
+ ASSERT_TRUE(DPI);
+ Var = DPI->getVariable();
+ Expr = DPI->getExpression();
+ Loc = DPI->getDebugLoc().get();
+ MLoc = DPI->getRawLocation();
+
+ // Test the creation of a DPValue and it's conversion back to a dbg.value.
+ DPV1 = new DPValue(DPI);
+ EXPECT_EQ(DPV1->getVariable(), Var);
+ EXPECT_EQ(DPV1->getExpression(), Expr);
+ EXPECT_EQ(DPV1->getDebugLoc().get(), Loc);
+ EXPECT_EQ(DPV1->getRawLocation(), MLoc);
+
+ // Erase dbg.value,
+ DPI->eraseFromParent();
+ // Re-create from DPV1, inserting at front.
+ DPV1->createDebugIntrinsic(&*M,
+ &M->getFunction("f")->getEntryBlock().front());
+
+ Instruction *NewDPI = &M->getFunction("f")->getEntryBlock().front();
+ DbgValueInst *DPI2 = dyn_cast<DbgValueInst>(NewDPI);
+ ASSERT_TRUE(DPI2);
+ EXPECT_EQ(DPI2->getVariable(), Var);
+ EXPECT_EQ(DPI2->getExpression(), Expr);
+ EXPECT_EQ(DPI2->getDebugLoc().get(), Loc);
+ EXPECT_EQ(DPI2->getRawLocation(), MLoc);
+ }
+
+ // Fetch the second dbg.value, convert it to a DPValue,
+ BasicBlock::iterator It = M->getFunction("f")->getEntryBlock().begin();
+ It = std::next(std::next(It));
+ DbgValueInst *DPI3 = dyn_cast<DbgValueInst>(It);
+ ASSERT_TRUE(DPI3);
+ DPValue *DPV2 = new DPValue(DPI3);
+
+ // These dbg.values are supposed to refer to different values.
+ EXPECT_NE(DPV1->getRawLocation(), DPV2->getRawLocation());
+
+ // Try manipulating DPValues and markers in the exit block.
+ BasicBlock *ExitBlock = &*std::next(M->getFunction("f")->getEntryBlock().getIterator());
+ Instruction *FirstInst = &ExitBlock->front();
+ Instruction *RetInst = &*std::next(FirstInst->getIterator());
+
+ // Set-up DPMarkers in this block.
+ ExitBlock->IsNewDbgInfoFormat = true;
+ ExitBlock->createMarker(FirstInst);
+ ExitBlock->createMarker(RetInst);
+
+ // Insert DPValues into markers, order should come out DPV2, DPV1.
+ FirstInst->DbgMarker->insertDPValue(DPV1, false);
+ FirstInst->DbgMarker->insertDPValue(DPV2, true);
+ unsigned int ItCount = 0;
+ for (DPValue &Item : FirstInst->DbgMarker->getDbgValueRange()) {
+ EXPECT_TRUE((&Item == DPV2 && ItCount == 0) ||
+ (&Item == DPV1 && ItCount == 1));
+ EXPECT_EQ(Item.getMarker(), FirstInst->DbgMarker);
+ ++ItCount;
+ }
+
+ // Clone them onto the second marker -- should allocate new DPVs.
+ RetInst->DbgMarker->cloneDebugInfoFrom(FirstInst->DbgMarker, std::nullopt, false);
+ EXPECT_EQ(RetInst->DbgMarker->StoredDPValues.size(), 2u);
+ ItCount = 0;
+ // Check these things store the same information; but that they're not the same
+ // objects.
+ for (DPValue &Item : RetInst->DbgMarker->getDbgValueRange()) {
+ EXPECT_TRUE((Item.getRawLocation() == DPV2->getRawLocation() && ItCount == 0) ||
+ (Item.getRawLocation() == DPV1->getRawLocation() && ItCount == 1));
+
+ EXPECT_EQ(Item.getMarker(), RetInst->DbgMarker);
+ EXPECT_NE(&Item, DPV1);
+ EXPECT_NE(&Item, DPV2);
+ ++ItCount;
+ }
+
+ RetInst->DbgMarker->dropDPValues();
+ EXPECT_EQ(RetInst->DbgMarker->StoredDPValues.size(), 0u);
+
+ // Try cloning one single DPValue.
+ auto DIIt = std::next(FirstInst->DbgMarker->getDbgValueRange().begin());
+ RetInst->DbgMarker->cloneDebugInfoFrom(FirstInst->DbgMarker, DIIt, false);
+ EXPECT_EQ(RetInst->DbgMarker->StoredDPValues.size(), 1u);
+ // The second DPValue should have been cloned; it should have the same values
+ // as DPV1.
+ EXPECT_EQ(RetInst->DbgMarker->StoredDPValues.begin()->getRawLocation(),
+ DPV1->getRawLocation());
+ // We should be able to drop individual DPValues.
+ RetInst->DbgMarker->dropOneDPValue(&*RetInst->DbgMarker->StoredDPValues.begin());
+
+ // "Aborb" a DPMarker: this means pretend that the instruction it's attached
+ // to is disappearing so it needs to be transferred into "this" marker.
+ RetInst->DbgMarker->absorbDebugValues(*FirstInst->DbgMarker, true);
+ EXPECT_EQ(RetInst->DbgMarker->StoredDPValues.size(), 2u);
+ // Should be the DPV1 and DPV2 objects.
+ ItCount = 0;
+ for (DPValue &Item : RetInst->DbgMarker->getDbgValueRange()) {
+ EXPECT_TRUE((&Item == DPV2 && ItCount == 0) ||
+ (&Item == DPV1 && ItCount == 1));
+ EXPECT_EQ(Item.getMarker(), RetInst->DbgMarker);
+ ++ItCount;
+ }
+
+ // Finally -- there are two DPValues left over. If we remove evrything in the
+ // basic block, then they should sink down into the "TrailingDPValues"
+ // container for dangling debug-info. Future facilities will restore them
+ // back when a terminator is inserted.
+ FirstInst->DbgMarker->removeMarker();
+ FirstInst->eraseFromParent();
+ RetInst->DbgMarker->removeMarker();
+ RetInst->eraseFromParent();
+
+ DPMarker *EndMarker = ExitBlock->getTrailingDPValues();
+ ASSERT_NE(EndMarker, nullptr);
+ EXPECT_EQ(EndMarker->StoredDPValues.size(), 2u);
+ // Test again that it's those two DPValues, DPV1 and DPV2.
+ ItCount = 0;
+ for (DPValue &Item : EndMarker->getDbgValueRange()) {
+ EXPECT_TRUE((&Item == DPV2 && ItCount == 0) ||
+ (&Item == DPV1 && ItCount == 1));
+ EXPECT_EQ(Item.getMarker(), EndMarker);
+ ++ItCount;
+ }
+
+ // Cleanup the trailing DPValue records and marker.
+ EndMarker->eraseFromParent();
+
+ // The record of those trailing DPValues would dangle and cause an assertion
+ // failure if it lived until the end of the LLVMContext.
+ ExitBlock->deleteTrailingDPValues();
+}
+
+TEST(MetadataTest, DPValueConversionRoutines) {
+ LLVMContext C;
+
+ // For the purpose of this test, set and un-set the command line option
+ // corresponding to UseNewDbgInfoFormat.
+ UseNewDbgInfoFormat = true;
+
+ std::unique_ptr<Module> M = parseIR(C, R"(
+ define i16 @f(i16 %a) !dbg !6 {
+ call void @llvm.dbg.value(metadata i16 %a, metadata !9, metadata !DIExpression()), !dbg !11
+ %b = add i16 %a, 1, !dbg !11
+ call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), !dbg !11
+ ret i16 0, !dbg !11
+
+ exit:
+ %c = add i16 %b, 1, !dbg !11
+ ret i16 0, !dbg !11
+ }
+ declare void @llvm.dbg.value(metadata, metadata, metadata) #0
+ attributes #0 = { nounwind readnone speculatable willreturn }
+
+ !llvm.dbg.cu = !{!0}
+ !llvm.module.flags = !{!5}
+
+ !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
+ !1 = !DIFile(filename: "t.ll", directory: "/")
+ !2 = !{}
+ !5 = !{i32 2, !"Debug Info Version", i32 3}
+ !6 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)
+ !7 = !DISubroutineType(types: !2)
+ !8 = !{!9}
+ !9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10)
+ !10 = !DIBasicType(name: "ty16", size: 16, encoding: DW_ATE_unsigned)
+ !11 = !DILocation(line: 1, column: 1, scope: !6)
+)");
+
+ // Check that the conversion routines and utilities between dbg.value
+ // debug-info format and DPValues works.
+ Function *F = M->getFunction("f");
+ BasicBlock *BB1 = &F->getEntryBlock();
+ // First instruction should be a dbg.value.
+ EXPECT_TRUE(isa<DbgValueInst>(BB1->front()));
+ EXPECT_FALSE(BB1->IsNewDbgInfoFormat);
+ // Validating the block for DPValues / DPMarkers shouldn't fail -- there's
+ // no data stored right now.
+ EXPECT_FALSE(BB1->validateDbgValues(false, false));
+
+ // Function and module should be marked as not having the new format too.
+ EXPECT_FALSE(F->IsNewDbgInfoFormat);
+ EXPECT_FALSE(M->IsNewDbgInfoFormat);
+
+ // Now convert.
+ M->convertToNewDbgValues();
+ EXPECT_TRUE(M->IsNewDbgInfoFormat);
+ EXPECT_TRUE(F->IsNewDbgInfoFormat);
+ EXPECT_TRUE(BB1->IsNewDbgInfoFormat);
+
+ // There should now be no dbg.value instructions!
+ // Ensure the first instruction exists, the test all of them.
+ EXPECT_FALSE(isa<DbgValueInst>(BB1->front()));
+ for (auto &BB : *F)
+ for (auto &I : BB)
+ EXPECT_FALSE(isa<DbgValueInst>(I));
+
+ // There should be a DPMarker on each of the two instructions in the entry
+ // block, each containing one DPValue.
+ EXPECT_EQ(BB1->size(), 2u);
+ Instruction *FirstInst = &BB1->front();
+ Instruction *SecondInst = FirstInst->getNextNode();
+ ASSERT_TRUE(FirstInst->DbgMarker);
+ ASSERT_TRUE(SecondInst->DbgMarker);
+ EXPECT_NE(FirstInst->DbgMarker, SecondInst->DbgMarker);
+ EXPECT_EQ(FirstInst, FirstInst->DbgMarker->MarkedInstr);
+ EXPECT_EQ(SecondInst, SecondInst->DbgMarker->MarkedInstr);
+
+ EXPECT_EQ(FirstInst->DbgMarker->StoredDPValues.size(), 1u);
+ DPValue *DPV1 = &*FirstInst->DbgMarker->getDbgValueRange().begin();
+ EXPECT_EQ(DPV1->getMarker(), FirstInst->DbgMarker);
+ // Should point at %a, an argument.
+ EXPECT_TRUE(isa<Argument>(DPV1->getVariableLocationOp(0)));
+
+ EXPECT_EQ(SecondInst->DbgMarker->StoredDPValues.size(), 1u);
+ DPValue *DPV2 = &*SecondInst->DbgMarker->getDbgValueRange().begin();
+ EXPECT_EQ(DPV2->getMarker(), SecondInst->DbgMarker);
+ // Should point at FirstInst.
+ EXPECT_EQ(DPV2->getVariableLocationOp(0), FirstInst);
+
+ // There should be no DPValues / DPMarkers in the second block, but it should
+ // be marked as being in the new format.
+ BasicBlock *BB2 = BB1->getNextNode();
+ EXPECT_TRUE(BB2->IsNewDbgInfoFormat);
+ for (auto &Inst : *BB2)
+ // Either there should be no marker, or it should be empty.
+ EXPECT_TRUE(!Inst.DbgMarker || Inst.DbgMarker->StoredDPValues.empty());
+
+ // Validating the first block should continue to not be a problem,
+ EXPECT_FALSE(BB1->validateDbgValues(false, false));
+ // But if we were to break something, it should be able to fire. Don't attempt
+ // to comprehensively test the validator, it's a smoke-test rather than a
+ // "proper" verification pass.
+ DPV1->setMarker(nullptr);
+ // A marker pointing the wrong way should be an error.
+ EXPECT_TRUE(BB1->validateDbgValues(false, false));
+ DPV1->setMarker(FirstInst->DbgMarker);
+
+ DILocalVariable *DLV1 = DPV1->getVariable();
+ DIExpression *Expr1 = DPV1->getExpression();
+ DILocalVariable *DLV2 = DPV2->getVariable();
+ DIExpression *Expr2 = DPV2->getExpression();
+
+ // Convert everything back to the "old" format and ensure it's right.
+ M->convertFromNewDbgValues();
+ EXPECT_FALSE(M->IsNewDbgInfoFormat);
+ EXPECT_FALSE(F->IsNewDbgInfoFormat);
+ EXPECT_FALSE(BB1->IsNewDbgInfoFormat);
+
+ EXPECT_EQ(BB1->size(), 4u);
+ ASSERT_TRUE(isa<DbgValueInst>(BB1->front()));
+ DbgValueInst *DVI1 = cast<DbgValueInst>(&BB1->front());
+ // These dbg.values should still point at the same places.
+ EXPECT_TRUE(isa<Argument>(DVI1->getVariableLocationOp(0)));
+ DbgValueInst *DVI2 = cast<DbgValueInst>(DVI1->getNextNode()->getNextNode());
+ EXPECT_EQ(DVI2->getVariableLocationOp(0), FirstInst);
+
+ // Check a few fields too,
+ EXPECT_EQ(DVI1->getVariable(), DLV1);
+ EXPECT_EQ(DVI1->getExpression(), Expr1);
+ EXPECT_EQ(DVI2->getVariable(), DLV2);
+ EXPECT_EQ(DVI2->getExpression(), Expr2);
+
+ UseNewDbgInfoFormat = false;
+}
+
} // end namespace
diff --git a/llvm/unittests/Transforms/Utils/LocalTest.cpp b/llvm/unittests/Transforms/Utils/LocalTest.cpp
index a27af6e..8225774 100644
--- a/llvm/unittests/Transforms/Utils/LocalTest.cpp
+++ b/llvm/unittests/Transforms/Utils/LocalTest.cpp
@@ -15,6 +15,7 @@
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/DIBuilder.h"
#include "llvm/IR/DebugInfo.h"
+#include "llvm/IR/DebugProgramInstruction.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
@@ -1277,3 +1278,69 @@ TEST(Local, ExpressionForConstant) {
Expr = createExpression(ConstantFP::get(PPC_FP128Ty, 32), PPC_FP128Ty);
EXPECT_EQ(Expr, nullptr);
}
+
+TEST(Local, ReplaceDPValue) {
+ LLVMContext C;
+
+ // Test that RAUW also replaces the operands of DPValue objects, i.e.
+ // non-instruction stored debugging information.
+ std::unique_ptr<Module> M = parseIR(C,
+ R"(
+ declare void @llvm.dbg.value(metadata, metadata, metadata)
+ define void @f(i32 %a) !dbg !8 {
+ entry:
+ %foo = add i32 %a, 1, !dbg !13
+ %bar = add i32 %foo, 0, !dbg !13
+ call void @llvm.dbg.value(metadata i32 %bar, metadata !11, metadata !DIExpression()), !dbg !13
+ ret void, !dbg !14
+ }
+ !llvm.dbg.cu = !{!0}
+ !llvm.module.flags = !{!3, !4}
+ !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 6.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
+ !1 = !DIFile(filename: "t2.c", directory: "foo")
+ !2 = !{}
+ !3 = !{i32 2, !"Dwarf Version", i32 4}
+ !4 = !{i32 2, !"Debug Info Version", i32 3}
+ !8 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 1, type: !9, isLocal: false, isDefinition: true, scopeLine: 1, isOptimized: false, unit: !0, retainedNodes: !2)
+ !9 = !DISubroutineType(types: !10)
+ !10 = !{null}
+ !11 = !DILocalVariable(name: "x", scope: !8, file: !1, line: 2, type: !12)
+ !12 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+ !13 = !DILocation(line: 2, column: 7, scope: !8)
+ !14 = !DILocation(line: 3, column: 1, scope: !8)
+ )");
+ auto *GV = M->getNamedValue("f");
+ ASSERT_TRUE(GV);
+ auto *F = dyn_cast<Function>(GV);
+ ASSERT_TRUE(F);
+ BasicBlock::iterator It = F->front().begin();
+ Instruction *FooInst = &*It;
+ It = std::next(It);
+ Instruction *BarInst = &*It;
+ It = std::next(It);
+ DbgValueInst *DVI = dyn_cast<DbgValueInst>(It);
+ ASSERT_TRUE(DVI);
+ It = std::next(It);
+ Instruction *RetInst = &*It;
+
+ // Convert DVI into a DPValue.
+ RetInst->DbgMarker = new DPMarker();
+ RetInst->DbgMarker->MarkedInstr = RetInst;
+ DPValue *DPV = new DPValue(DVI);
+ RetInst->DbgMarker->insertDPValue(DPV, false);
+ // ... and erase the dbg.value.
+ DVI->eraseFromParent();
+
+ // DPV should originally refer to %bar,
+ EXPECT_EQ(DPV->getVariableLocationOp(0), BarInst);
+
+ // Now try to replace the computation of %bar with %foo -- this should cause
+ // the DPValue's to have it's operand updated beneath it.
+ BarInst->replaceAllUsesWith(FooInst);
+ // Check DPV now points at %foo.
+ EXPECT_EQ(DPV->getVariableLocationOp(0), FooInst);
+
+ // Teardown.
+ RetInst->DbgMarker->eraseFromParent();
+}
+
diff --git a/llvm/utils/gn/secondary/llvm/lib/IR/BUILD.gn b/llvm/utils/gn/secondary/llvm/lib/IR/BUILD.gn
index 298f449..8c2e8ab 100644
--- a/llvm/utils/gn/secondary/llvm/lib/IR/BUILD.gn
+++ b/llvm/utils/gn/secondary/llvm/lib/IR/BUILD.gn
@@ -31,6 +31,7 @@ static_library("IR") {
"DataLayout.cpp",
"DebugInfo.cpp",
"DebugInfoMetadata.cpp",
+ "DebugProgramInstruction.cpp",
"DebugLoc.cpp",
"DiagnosticHandler.cpp",
"DiagnosticInfo.cpp",