aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/llvm/lib/IR/DebugProgramInstruction.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2023-12-18 20:30:12 +0000
committerDimitry Andric <dim@FreeBSD.org>2024-04-19 21:12:03 +0000
commitc9157d925c489f07ba9c0b2ce47e5149b75969a5 (patch)
tree08bc4a3d9cad3f9ebffa558ddf140b9d9257b219 /contrib/llvm-project/llvm/lib/IR/DebugProgramInstruction.cpp
parent2a66844f606a35d68ad8a8061f4bea204274b3bc (diff)
Diffstat (limited to 'contrib/llvm-project/llvm/lib/IR/DebugProgramInstruction.cpp')
-rw-r--r--contrib/llvm-project/llvm/lib/IR/DebugProgramInstruction.cpp388
1 files changed, 388 insertions, 0 deletions
diff --git a/contrib/llvm-project/llvm/lib/IR/DebugProgramInstruction.cpp b/contrib/llvm-project/llvm/lib/IR/DebugProgramInstruction.cpp
new file mode 100644
index 000000000000..7b709a2de033
--- /dev/null
+++ b/contrib/llvm-project/llvm/lib/IR/DebugProgramInstruction.cpp
@@ -0,0 +1,388 @@
+//======-- 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/DebugInfoMetadata.h"
+#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, LocationType Type)
+ : DebugValueUser(Location), Variable(DV), Expression(Expr), DbgLoc(DI),
+ Type(Type) {}
+
+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))};
+}
+
+unsigned DPValue::getNumVariableLocationOps() const {
+ if (hasArgList())
+ return cast<DIArgList>(getRawLocation())->getArgs().size();
+ return 1;
+}
+
+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));
+}
+
+void DPValue::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 DPValue::isKillLocation() const {
+ return (getNumVariableLocationOps() == 0 &&
+ !getExpression()->isComplex()) ||
+ any_of(location_ops(), [](Value *V) { return isa<UndefValue>(V); });
+}
+
+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;
+ case DPValue::LocationType::End:
+ case DPValue::LocationType::Any:
+ llvm_unreachable("Invalid LocationType");
+ 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.
+ DPMarker *NextMarker = Owner->getParent()->getNextMarker(Owner);
+ if (NextMarker == nullptr) {
+ NextMarker = new DPMarker();
+ Owner->getParent()->setTrailingDPValues(NextMarker);
+ }
+ 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);
+}
+
+void DPMarker::absorbDebugValues(iterator_range<DPValue::self_iterator> Range,
+ DPMarker &Src, bool InsertAtHead) {
+ for (DPValue &DPV : Range)
+ DPV.setMarker(this);
+
+ auto InsertPos =
+ (InsertAtHead) ? StoredDPValues.begin() : StoredDPValues.end();
+
+ StoredDPValues.splice(InsertPos, Src.StoredDPValues, Range.begin(),
+ Range.end());
+}
+
+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
+