diff options
Diffstat (limited to 'contrib/llvm-project/llvm/lib/IR/DebugProgramInstruction.cpp')
| -rw-r--r-- | contrib/llvm-project/llvm/lib/IR/DebugProgramInstruction.cpp | 388 | 
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 +  | 
