//======-- 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_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(nullptr)), location_op_iterator(static_cast(nullptr))}; // If operand is ValueAsMetadata, return a range over just that operand. if (auto *VAM = dyn_cast(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(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(MD)->getNumOperands() == 0); return {location_op_iterator(static_cast(nullptr)), location_op_iterator(static_cast(nullptr))}; } unsigned DPValue::getNumVariableLocationOps() const { if (hasArgList()) return cast(getRawLocation())->getArgs().size(); return 1; } Value *DPValue::getVariableLocationOp(unsigned OpIdx) const { auto *MD = getRawLocation(); if (!MD) return nullptr; if (auto *AL = dyn_cast(MD)) return AL->getArgs()[OpIdx]->getValue(); if (isa(MD)) return nullptr; assert(isa(MD) && "Attempted to get location operand from DPValue with none."); auto *V = cast(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(V) ? dyn_cast( cast(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(NewValue) ? cast(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 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(NewValue) ? cast(NewValue)->getMetadata() : ValueAsMetadata::get(NewValue)); return; } SmallVector 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 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 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 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(V); }); } std::optional 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( 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 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 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::iterator> DPMarker::cloneDebugInfoFrom( DPMarker *From, std::optional::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