mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-25 20:23:11 +01:00
Partial Reapply "[DebugInfo] Use variadic debug values to salvage BinOps and GEP instrs with non-const operands"
This is a partial reapply of the original commit and the followup commit that were previously reverted; this reapply also includes a small fix for a potential source of non-determinism, but also has a small change to turn off variadic debug value salvaging, to ensure that any future revert/reapply steps to disable and renable this feature do not risk causing conflicts. Differential Revision: https://reviews.llvm.org/D91722 This reverts commit 386b66b2fc297cda121a3cc8a36887a6ecbcfc68.
This commit is contained in:
parent
41f14edc36
commit
782c047ef4
@ -2592,6 +2592,16 @@ public:
|
|||||||
// return it's sign information.
|
// return it's sign information.
|
||||||
llvm::Optional<SignedOrUnsignedConstant> isConstant() const;
|
llvm::Optional<SignedOrUnsignedConstant> isConstant() const;
|
||||||
|
|
||||||
|
/// Return the number of unique location operands referred to (via
|
||||||
|
/// DW_OP_LLVM_arg) in this expression; this is not necessarily the number of
|
||||||
|
/// instances of DW_OP_LLVM_arg within the expression.
|
||||||
|
/// For example, for the expression:
|
||||||
|
/// (DW_OP_LLVM_arg 0, DW_OP_LLVM_arg 1, DW_OP_plus,
|
||||||
|
/// DW_OP_LLVM_arg 0, DW_OP_mul)
|
||||||
|
/// This function would return 2, as there are two unique location operands
|
||||||
|
/// (0 and 1).
|
||||||
|
uint64_t getNumLocationOperands() const;
|
||||||
|
|
||||||
using element_iterator = ArrayRef<uint64_t>::iterator;
|
using element_iterator = ArrayRef<uint64_t>::iterator;
|
||||||
|
|
||||||
element_iterator elements_begin() const { return getElements().begin(); }
|
element_iterator elements_begin() const { return getElements().begin(); }
|
||||||
@ -2739,6 +2749,10 @@ public:
|
|||||||
/// return true with an offset of zero.
|
/// return true with an offset of zero.
|
||||||
bool extractIfOffset(int64_t &Offset) const;
|
bool extractIfOffset(int64_t &Offset) const;
|
||||||
|
|
||||||
|
/// Returns true iff this DIExpression contains at least one instance of
|
||||||
|
/// `DW_OP_LLVM_arg, n` for all n in [0, N).
|
||||||
|
bool hasAllLocationOps(unsigned N) const;
|
||||||
|
|
||||||
/// Checks if the last 4 elements of the expression are DW_OP_constu <DWARF
|
/// Checks if the last 4 elements of the expression are DW_OP_constu <DWARF
|
||||||
/// Address Space> DW_OP_swap DW_OP_xderef and extracts the <DWARF Address
|
/// Address Space> DW_OP_swap DW_OP_xderef and extracts the <DWARF Address
|
||||||
/// Space>.
|
/// Space>.
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
#include "llvm/ADT/ArrayRef.h"
|
#include "llvm/ADT/ArrayRef.h"
|
||||||
#include "llvm/ADT/Bitfields.h"
|
#include "llvm/ADT/Bitfields.h"
|
||||||
|
#include "llvm/ADT/MapVector.h"
|
||||||
#include "llvm/ADT/None.h"
|
#include "llvm/ADT/None.h"
|
||||||
#include "llvm/ADT/STLExtras.h"
|
#include "llvm/ADT/STLExtras.h"
|
||||||
#include "llvm/ADT/SmallVector.h"
|
#include "llvm/ADT/SmallVector.h"
|
||||||
@ -1152,7 +1153,9 @@ public:
|
|||||||
/// must be at least as wide as the IntPtr type for the address space of
|
/// must be at least as wide as the IntPtr type for the address space of
|
||||||
/// the base GEP pointer.
|
/// the base GEP pointer.
|
||||||
bool accumulateConstantOffset(const DataLayout &DL, APInt &Offset) const;
|
bool accumulateConstantOffset(const DataLayout &DL, APInt &Offset) const;
|
||||||
|
bool collectOffset(const DataLayout &DL, unsigned BitWidth,
|
||||||
|
MapVector<Value *, APInt> &VariableOffsets,
|
||||||
|
APInt &ConstantOffset) const;
|
||||||
// Methods for support type inquiry through isa, cast, and dyn_cast:
|
// Methods for support type inquiry through isa, cast, and dyn_cast:
|
||||||
static bool classof(const Instruction *I) {
|
static bool classof(const Instruction *I) {
|
||||||
return (I->getOpcode() == Instruction::GetElementPtr);
|
return (I->getOpcode() == Instruction::GetElementPtr);
|
||||||
|
@ -204,6 +204,11 @@ public:
|
|||||||
|
|
||||||
void replaceVariableLocationOp(Value *OldValue, Value *NewValue);
|
void replaceVariableLocationOp(Value *OldValue, Value *NewValue);
|
||||||
void replaceVariableLocationOp(unsigned OpIdx, Value *NewValue);
|
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) {
|
void setVariable(DILocalVariable *NewVar) {
|
||||||
setArgOperand(1, MetadataAsValue::get(NewVar->getContext(), NewVar));
|
setArgOperand(1, MetadataAsValue::get(NewVar->getContext(), NewVar));
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
#ifndef LLVM_IR_OPERATOR_H
|
#ifndef LLVM_IR_OPERATOR_H
|
||||||
#define LLVM_IR_OPERATOR_H
|
#define LLVM_IR_OPERATOR_H
|
||||||
|
|
||||||
|
#include "llvm/ADT/MapVector.h"
|
||||||
#include "llvm/ADT/None.h"
|
#include "llvm/ADT/None.h"
|
||||||
#include "llvm/ADT/Optional.h"
|
#include "llvm/ADT/Optional.h"
|
||||||
#include "llvm/IR/Constants.h"
|
#include "llvm/IR/Constants.h"
|
||||||
@ -576,6 +577,12 @@ public:
|
|||||||
Type *SourceType, ArrayRef<const Value *> Index, const DataLayout &DL,
|
Type *SourceType, ArrayRef<const Value *> Index, const DataLayout &DL,
|
||||||
APInt &Offset,
|
APInt &Offset,
|
||||||
function_ref<bool(Value &, APInt &)> ExternalAnalysis = nullptr);
|
function_ref<bool(Value &, APInt &)> ExternalAnalysis = nullptr);
|
||||||
|
|
||||||
|
/// Collect the offset of this GEP as a map of Values to their associated
|
||||||
|
/// APInt multipliers, as well as a total Constant Offset.
|
||||||
|
bool collectOffset(const DataLayout &DL, unsigned BitWidth,
|
||||||
|
MapVector<Value *, APInt> &VariableOffsets,
|
||||||
|
APInt &ConstantOffset) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class PtrToIntOperator
|
class PtrToIntOperator
|
||||||
|
@ -298,7 +298,8 @@ void salvageDebugInfoForDbgValues(Instruction &I,
|
|||||||
/// appended to the expression. \p LocNo: the index of the location operand to
|
/// appended to the expression. \p LocNo: the index of the location operand to
|
||||||
/// which \p I applies, should be 0 for debug info without a DIArgList.
|
/// which \p I applies, should be 0 for debug info without a DIArgList.
|
||||||
DIExpression *salvageDebugInfoImpl(Instruction &I, DIExpression *DIExpr,
|
DIExpression *salvageDebugInfoImpl(Instruction &I, DIExpression *DIExpr,
|
||||||
bool StackVal, unsigned LocNo);
|
bool StackVal, unsigned LocNo,
|
||||||
|
SmallVectorImpl<Value *> &AdditionalValues);
|
||||||
|
|
||||||
/// Point debug users of \p From to \p To or salvage them. Use this function
|
/// Point debug users of \p From to \p To or salvage them. Use this function
|
||||||
/// only when replacing all uses of \p From with \p To, with a guarantee that
|
/// only when replacing all uses of \p From with \p To, with a guarantee that
|
||||||
|
@ -121,11 +121,6 @@ public:
|
|||||||
// Currently, DBG_VALUE_VAR expressions must use stack_value.
|
// Currently, DBG_VALUE_VAR expressions must use stack_value.
|
||||||
assert(Expr && Expr->isValid() &&
|
assert(Expr && Expr->isValid() &&
|
||||||
is_contained(Locs, dwarf::DW_OP_stack_value));
|
is_contained(Locs, dwarf::DW_OP_stack_value));
|
||||||
for (DbgValueLocEntry &Entry : ValueLocEntries) {
|
|
||||||
assert(!Entry.isConstantFP() && !Entry.isConstantInt() &&
|
|
||||||
"Constant values should only be present in non-variadic "
|
|
||||||
"DBG_VALUEs.");
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,11 +137,6 @@ public:
|
|||||||
// Currently, DBG_VALUE_VAR expressions must use stack_value.
|
// Currently, DBG_VALUE_VAR expressions must use stack_value.
|
||||||
assert(Expr && Expr->isValid() &&
|
assert(Expr && Expr->isValid() &&
|
||||||
is_contained(Expr->getElements(), dwarf::DW_OP_stack_value));
|
is_contained(Expr->getElements(), dwarf::DW_OP_stack_value));
|
||||||
for (DbgValueLocEntry &Entry : ValueLocEntries) {
|
|
||||||
assert(!Entry.isConstantFP() && !Entry.isConstantInt() &&
|
|
||||||
"Constant values should only be present in non-variadic "
|
|
||||||
"DBG_VALUEs.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -1248,6 +1248,10 @@ void SelectionDAGBuilder::resolveDanglingDebugInfo(const Value *V,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SelectionDAGBuilder::salvageUnresolvedDbgValue(DanglingDebugInfo &DDI) {
|
void SelectionDAGBuilder::salvageUnresolvedDbgValue(DanglingDebugInfo &DDI) {
|
||||||
|
// TODO: For the variadic implementation, instead of only checking the fail
|
||||||
|
// state of `handleDebugValue`, we need know specifically which values were
|
||||||
|
// invalid, so that we attempt to salvage only those values when processing
|
||||||
|
// a DIArgList.
|
||||||
assert(!DDI.getDI()->hasArgList() &&
|
assert(!DDI.getDI()->hasArgList() &&
|
||||||
"Not implemented for variadic dbg_values");
|
"Not implemented for variadic dbg_values");
|
||||||
Value *V = DDI.getDI()->getValue(0);
|
Value *V = DDI.getDI()->getValue(0);
|
||||||
@ -1271,16 +1275,21 @@ void SelectionDAGBuilder::salvageUnresolvedDbgValue(DanglingDebugInfo &DDI) {
|
|||||||
while (isa<Instruction>(V)) {
|
while (isa<Instruction>(V)) {
|
||||||
Instruction &VAsInst = *cast<Instruction>(V);
|
Instruction &VAsInst = *cast<Instruction>(V);
|
||||||
// Temporary "0", awaiting real implementation.
|
// Temporary "0", awaiting real implementation.
|
||||||
DIExpression *NewExpr = salvageDebugInfoImpl(VAsInst, Expr, StackValue, 0);
|
SmallVector<Value *, 4> AdditionalValues;
|
||||||
|
DIExpression *SalvagedExpr =
|
||||||
|
salvageDebugInfoImpl(VAsInst, Expr, StackValue, 0, AdditionalValues);
|
||||||
|
|
||||||
// If we cannot salvage any further, and haven't yet found a suitable debug
|
// If we cannot salvage any further, and haven't yet found a suitable debug
|
||||||
// expression, bail out.
|
// expression, bail out.
|
||||||
if (!NewExpr)
|
// TODO: If AdditionalValues isn't empty, then the salvage can only be
|
||||||
|
// represented with a DBG_VALUE_LIST, so we give up. When we have support
|
||||||
|
// here for variadic dbg_values, remove that condition.
|
||||||
|
if (!SalvagedExpr || !AdditionalValues.empty())
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// New value and expr now represent this debuginfo.
|
// New value and expr now represent this debuginfo.
|
||||||
V = VAsInst.getOperand(0);
|
V = VAsInst.getOperand(0);
|
||||||
Expr = NewExpr;
|
Expr = SalvagedExpr;
|
||||||
|
|
||||||
// Some kind of simplification occurred: check whether the operand of the
|
// Some kind of simplification occurred: check whether the operand of the
|
||||||
// salvaged debug expression can be encoded in this DAG.
|
// salvaged debug expression can be encoded in this DAG.
|
||||||
|
@ -1251,6 +1251,17 @@ bool DIExpression::extractIfOffset(int64_t &Offset) const {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool DIExpression::hasAllLocationOps(unsigned N) const {
|
||||||
|
SmallDenseSet<uint64_t, 4> SeenOps;
|
||||||
|
for (auto ExprOp : expr_ops())
|
||||||
|
if (ExprOp.getOp() == dwarf::DW_OP_LLVM_arg)
|
||||||
|
SeenOps.insert(ExprOp.getArg(0));
|
||||||
|
for (uint64_t Idx = 0; Idx < N; ++Idx)
|
||||||
|
if (!is_contained(SeenOps, Idx))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
const DIExpression *DIExpression::extractAddressClass(const DIExpression *Expr,
|
const DIExpression *DIExpression::extractAddressClass(const DIExpression *Expr,
|
||||||
unsigned &AddrClass) {
|
unsigned &AddrClass) {
|
||||||
// FIXME: This seems fragile. Nothing that verifies that these elements
|
// FIXME: This seems fragile. Nothing that verifies that these elements
|
||||||
@ -1465,6 +1476,16 @@ Optional<DIExpression *> DIExpression::createFragmentExpression(
|
|||||||
return DIExpression::get(Expr->getContext(), Ops);
|
return DIExpression::get(Expr->getContext(), Ops);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t DIExpression::getNumLocationOperands() const {
|
||||||
|
uint64_t Result = 0;
|
||||||
|
for (auto ExprOp : expr_ops())
|
||||||
|
if (ExprOp.getOp() == dwarf::DW_OP_LLVM_arg)
|
||||||
|
Result = std::max(Result, ExprOp.getArg(0) + 1);
|
||||||
|
assert(hasAllLocationOps(Result) &&
|
||||||
|
"Expression is missing one or more location operands.");
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
llvm::Optional<DIExpression::SignedOrUnsignedConstant>
|
llvm::Optional<DIExpression::SignedOrUnsignedConstant>
|
||||||
DIExpression::isConstant() const {
|
DIExpression::isConstant() const {
|
||||||
|
|
||||||
|
@ -1804,6 +1804,15 @@ bool GetElementPtrInst::accumulateConstantOffset(const DataLayout &DL,
|
|||||||
return cast<GEPOperator>(this)->accumulateConstantOffset(DL, Offset);
|
return cast<GEPOperator>(this)->accumulateConstantOffset(DL, Offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GetElementPtrInst::collectOffset(
|
||||||
|
const DataLayout &DL, unsigned BitWidth,
|
||||||
|
MapVector<Value *, APInt> &VariableOffsets,
|
||||||
|
APInt &ConstantOffset) const {
|
||||||
|
// Delegate to the generic GEPOperator implementation.
|
||||||
|
return cast<GEPOperator>(this)->collectOffset(DL, BitWidth, VariableOffsets,
|
||||||
|
ConstantOffset);
|
||||||
|
}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// ExtractElementInst Implementation
|
// ExtractElementInst Implementation
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
@ -118,6 +118,23 @@ void DbgVariableIntrinsic::replaceVariableLocationOp(unsigned OpIdx,
|
|||||||
0, MetadataAsValue::get(getContext(), DIArgList::get(getContext(), MDs)));
|
0, MetadataAsValue::get(getContext(), DIArgList::get(getContext(), MDs)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DbgVariableIntrinsic::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");
|
||||||
|
setArgOperand(2, MetadataAsValue::get(getContext(), NewExpr));
|
||||||
|
SmallVector<ValueAsMetadata *, 4> MDs;
|
||||||
|
for (auto *VMD : location_ops())
|
||||||
|
MDs.push_back(getAsMetadata(VMD));
|
||||||
|
for (auto *VMD : NewValues)
|
||||||
|
MDs.push_back(getAsMetadata(VMD));
|
||||||
|
setArgOperand(
|
||||||
|
0, MetadataAsValue::get(getContext(), DIArgList::get(getContext(), MDs)));
|
||||||
|
}
|
||||||
|
|
||||||
Optional<uint64_t> DbgVariableIntrinsic::getFragmentSizeInBits() const {
|
Optional<uint64_t> DbgVariableIntrinsic::getFragmentSizeInBits() const {
|
||||||
if (auto Fragment = getExpression()->getFragmentInfo())
|
if (auto Fragment = getExpression()->getFragmentInfo())
|
||||||
return Fragment->SizeInBits;
|
return Fragment->SizeInBits;
|
||||||
|
@ -142,4 +142,61 @@ bool GEPOperator::accumulateConstantOffset(
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GEPOperator::collectOffset(
|
||||||
|
const DataLayout &DL, unsigned BitWidth,
|
||||||
|
MapVector<Value *, APInt> &VariableOffsets,
|
||||||
|
APInt &ConstantOffset) const {
|
||||||
|
assert(BitWidth == DL.getIndexSizeInBits(getPointerAddressSpace()) &&
|
||||||
|
"The offset bit width does not match DL specification.");
|
||||||
|
|
||||||
|
auto CollectConstantOffset = [&](APInt Index, uint64_t Size) {
|
||||||
|
Index = Index.sextOrTrunc(BitWidth);
|
||||||
|
APInt IndexedSize = APInt(BitWidth, Size);
|
||||||
|
ConstantOffset += Index * IndexedSize;
|
||||||
|
};
|
||||||
|
|
||||||
|
for (gep_type_iterator GTI = gep_type_begin(this), GTE = gep_type_end(this);
|
||||||
|
GTI != GTE; ++GTI) {
|
||||||
|
// Scalable vectors are multiplied by a runtime constant.
|
||||||
|
bool ScalableType = isa<ScalableVectorType>(GTI.getIndexedType());
|
||||||
|
|
||||||
|
Value *V = GTI.getOperand();
|
||||||
|
StructType *STy = GTI.getStructTypeOrNull();
|
||||||
|
// Handle ConstantInt if possible.
|
||||||
|
if (auto ConstOffset = dyn_cast<ConstantInt>(V)) {
|
||||||
|
if (ConstOffset->isZero())
|
||||||
|
continue;
|
||||||
|
// If the type is scalable and the constant is not zero (vscale * n * 0 =
|
||||||
|
// 0) bailout.
|
||||||
|
// TODO: If the runtime value is accessible at any point before DWARF
|
||||||
|
// emission, then we could potentially keep a forward reference to it
|
||||||
|
// in the debug value to be filled in later.
|
||||||
|
if (ScalableType)
|
||||||
|
return false;
|
||||||
|
// Handle a struct index, which adds its field offset to the pointer.
|
||||||
|
if (STy) {
|
||||||
|
unsigned ElementIdx = ConstOffset->getZExtValue();
|
||||||
|
const StructLayout *SL = DL.getStructLayout(STy);
|
||||||
|
// Element offset is in bytes.
|
||||||
|
CollectConstantOffset(APInt(BitWidth, SL->getElementOffset(ElementIdx)),
|
||||||
|
1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
CollectConstantOffset(ConstOffset->getValue(),
|
||||||
|
DL.getTypeAllocSize(GTI.getIndexedType()));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (STy || ScalableType)
|
||||||
|
return false;
|
||||||
|
// Insert an initial offset of 0 for V iff none exists already, then
|
||||||
|
// increment the offset by IndexedSize.
|
||||||
|
VariableOffsets.insert({V, APInt(BitWidth, 0)});
|
||||||
|
APInt IndexedSize =
|
||||||
|
APInt(BitWidth, DL.getTypeAllocSize(GTI.getIndexedType()));
|
||||||
|
VariableOffsets[V] += IndexedSize;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
} // namespace llvm
|
} // namespace llvm
|
||||||
|
@ -2488,10 +2488,15 @@ void coro::salvageDebugInfo(
|
|||||||
} else if (auto *StInst = dyn_cast<StoreInst>(Storage)) {
|
} else if (auto *StInst = dyn_cast<StoreInst>(Storage)) {
|
||||||
Storage = StInst->getOperand(0);
|
Storage = StInst->getOperand(0);
|
||||||
} else if (auto *GEPInst = dyn_cast<GetElementPtrInst>(Storage)) {
|
} else if (auto *GEPInst = dyn_cast<GetElementPtrInst>(Storage)) {
|
||||||
Expr = llvm::salvageDebugInfoImpl(*GEPInst, Expr,
|
SmallVector<Value *> AdditionalValues;
|
||||||
/*WithStackValue=*/false, 0);
|
DIExpression *SalvagedExpr = llvm::salvageDebugInfoImpl(
|
||||||
if (!Expr)
|
*GEPInst, Expr,
|
||||||
return;
|
/*WithStackValue=*/false, 0, AdditionalValues);
|
||||||
|
// Debug declares cannot currently handle additional location
|
||||||
|
// operands.
|
||||||
|
if (!SalvagedExpr || !AdditionalValues.empty())
|
||||||
|
break;
|
||||||
|
Expr = SalvagedExpr;
|
||||||
Storage = GEPInst->getOperand(0);
|
Storage = GEPInst->getOperand(0);
|
||||||
} else if (auto *BCInst = dyn_cast<llvm::BitCastInst>(Storage))
|
} else if (auto *BCInst = dyn_cast<llvm::BitCastInst>(Storage))
|
||||||
Storage = BCInst->getOperand(0);
|
Storage = BCInst->getOperand(0);
|
||||||
|
@ -1718,6 +1718,9 @@ void llvm::salvageDebugInfo(Instruction &I) {
|
|||||||
|
|
||||||
void llvm::salvageDebugInfoForDbgValues(
|
void llvm::salvageDebugInfoForDbgValues(
|
||||||
Instruction &I, ArrayRef<DbgVariableIntrinsic *> DbgUsers) {
|
Instruction &I, ArrayRef<DbgVariableIntrinsic *> DbgUsers) {
|
||||||
|
// This is an arbitrary chosen limit on the maximum number of values we can
|
||||||
|
// salvage up to in a DIArgList, used for performance reasons.
|
||||||
|
const unsigned MaxDebugArgs = 16;
|
||||||
bool Salvaged = false;
|
bool Salvaged = false;
|
||||||
|
|
||||||
for (auto *DII : DbgUsers) {
|
for (auto *DII : DbgUsers) {
|
||||||
@ -1730,17 +1733,34 @@ void llvm::salvageDebugInfoForDbgValues(
|
|||||||
is_contained(DIILocation, &I) &&
|
is_contained(DIILocation, &I) &&
|
||||||
"DbgVariableIntrinsic must use salvaged instruction as its location");
|
"DbgVariableIntrinsic must use salvaged instruction as its location");
|
||||||
unsigned LocNo = std::distance(DIILocation.begin(), find(DIILocation, &I));
|
unsigned LocNo = std::distance(DIILocation.begin(), find(DIILocation, &I));
|
||||||
|
SmallVector<Value *, 4> AdditionalValues;
|
||||||
DIExpression *DIExpr =
|
DIExpression *SalvagedExpr = salvageDebugInfoImpl(
|
||||||
salvageDebugInfoImpl(I, DII->getExpression(), StackValue, LocNo);
|
I, DII->getExpression(), StackValue, LocNo, AdditionalValues);
|
||||||
|
|
||||||
// salvageDebugInfoImpl should fail on examining the first element of
|
// salvageDebugInfoImpl should fail on examining the first element of
|
||||||
// DbgUsers, or none of them.
|
// DbgUsers, or none of them.
|
||||||
if (!DIExpr)
|
if (!SalvagedExpr)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
DII->replaceVariableLocationOp(&I, I.getOperand(0));
|
DII->replaceVariableLocationOp(&I, I.getOperand(0));
|
||||||
DII->setExpression(DIExpr);
|
if (AdditionalValues.empty()) {
|
||||||
|
DII->setExpression(SalvagedExpr);
|
||||||
|
} else if (isa<DbgValueInst>(DII) &&
|
||||||
|
DII->getNumVariableLocationOps() + AdditionalValues.size() <=
|
||||||
|
MaxDebugArgs) {
|
||||||
|
// TODO: Uncomment the line below and delete the two beneath it to enable
|
||||||
|
// salvaging of dbg.values with multiple location operands.
|
||||||
|
// DII->addVariableLocationOps(AdditionalValues, SalvagedExpr);
|
||||||
|
Value *Undef = UndefValue::get(I.getOperand(0)->getType());
|
||||||
|
DII->replaceVariableLocationOp(I.getOperand(0), Undef);
|
||||||
|
} else {
|
||||||
|
// Do not salvage using DIArgList for dbg.addr/dbg.declare, as it is
|
||||||
|
// currently only valid for stack value expressions.
|
||||||
|
// Also do not salvage if the resulting DIArgList would contain an
|
||||||
|
// unreasonably large number of values.
|
||||||
|
Value *Undef = UndefValue::get(I.getOperand(0)->getType());
|
||||||
|
DII->replaceVariableLocationOp(I.getOperand(0), Undef);
|
||||||
|
}
|
||||||
LLVM_DEBUG(dbgs() << "SALVAGE: " << *DII << '\n');
|
LLVM_DEBUG(dbgs() << "SALVAGE: " << *DII << '\n');
|
||||||
Salvaged = true;
|
Salvaged = true;
|
||||||
}
|
}
|
||||||
@ -1755,12 +1775,27 @@ void llvm::salvageDebugInfoForDbgValues(
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool getSalvageOpsForGEP(GetElementPtrInst *GEP, const DataLayout &DL,
|
bool getSalvageOpsForGEP(GetElementPtrInst *GEP, const DataLayout &DL,
|
||||||
SmallVectorImpl<uint64_t> &Opcodes) {
|
uint64_t CurrentLocOps,
|
||||||
|
SmallVectorImpl<uint64_t> &Opcodes,
|
||||||
|
SmallVectorImpl<Value *> &AdditionalValues) {
|
||||||
unsigned BitWidth = DL.getIndexSizeInBits(GEP->getPointerAddressSpace());
|
unsigned BitWidth = DL.getIndexSizeInBits(GEP->getPointerAddressSpace());
|
||||||
// Rewrite a constant GEP into a DIExpression.
|
// Rewrite a GEP into a DIExpression.
|
||||||
|
MapVector<Value *, APInt> VariableOffsets;
|
||||||
APInt ConstantOffset(BitWidth, 0);
|
APInt ConstantOffset(BitWidth, 0);
|
||||||
if (!GEP->accumulateConstantOffset(DL, ConstantOffset))
|
if (!GEP->collectOffset(DL, BitWidth, VariableOffsets, ConstantOffset))
|
||||||
return false;
|
return false;
|
||||||
|
if (!VariableOffsets.empty() && !CurrentLocOps) {
|
||||||
|
Opcodes.insert(Opcodes.begin(), {dwarf::DW_OP_LLVM_arg, 0});
|
||||||
|
CurrentLocOps = 1;
|
||||||
|
}
|
||||||
|
for (auto Offset : VariableOffsets) {
|
||||||
|
AdditionalValues.push_back(Offset.first);
|
||||||
|
assert(Offset.second.isStrictlyPositive() &&
|
||||||
|
"Expected strictly positive multiplier for offset.");
|
||||||
|
Opcodes.append({dwarf::DW_OP_LLVM_arg, CurrentLocOps++, dwarf::DW_OP_constu,
|
||||||
|
Offset.second.getZExtValue(), dwarf::DW_OP_mul,
|
||||||
|
dwarf::DW_OP_plus});
|
||||||
|
}
|
||||||
DIExpression::appendOffset(Opcodes, ConstantOffset.getSExtValue());
|
DIExpression::appendOffset(Opcodes, ConstantOffset.getSExtValue());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1795,14 +1830,19 @@ uint64_t getDwarfOpForBinOp(Instruction::BinaryOps Opcode) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool getSalvageOpsForBinOp(BinaryOperator *BI,
|
bool getSalvageOpsForBinOp(BinaryOperator *BI, uint64_t CurrentLocOps,
|
||||||
SmallVectorImpl<uint64_t> &Opcodes) {
|
SmallVectorImpl<uint64_t> &Opcodes,
|
||||||
// Rewrite binary operations with constant integer operands.
|
SmallVectorImpl<Value *> &AdditionalValues) {
|
||||||
|
// Handle binary operations with constant integer operands as a special case.
|
||||||
auto *ConstInt = dyn_cast<ConstantInt>(BI->getOperand(1));
|
auto *ConstInt = dyn_cast<ConstantInt>(BI->getOperand(1));
|
||||||
if (!ConstInt || ConstInt->getBitWidth() > 64)
|
// Values wider than 64 bits cannot be represented within a DIExpression.
|
||||||
|
if (ConstInt && ConstInt->getBitWidth() > 64)
|
||||||
return false;
|
return false;
|
||||||
uint64_t Val = ConstInt->getSExtValue();
|
|
||||||
Instruction::BinaryOps BinOpcode = BI->getOpcode();
|
Instruction::BinaryOps BinOpcode = BI->getOpcode();
|
||||||
|
// Push any Constant Int operand onto the expression stack.
|
||||||
|
if (ConstInt) {
|
||||||
|
uint64_t Val = ConstInt->getSExtValue();
|
||||||
// Add or Sub Instructions with a constant operand can potentially be
|
// Add or Sub Instructions with a constant operand can potentially be
|
||||||
// simplified.
|
// simplified.
|
||||||
if (BinOpcode == Instruction::Add || BinOpcode == Instruction::Sub) {
|
if (BinOpcode == Instruction::Add || BinOpcode == Instruction::Sub) {
|
||||||
@ -1810,8 +1850,15 @@ bool getSalvageOpsForBinOp(BinaryOperator *BI,
|
|||||||
DIExpression::appendOffset(Opcodes, Offset);
|
DIExpression::appendOffset(Opcodes, Offset);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// Add constant int operand to expression stack.
|
|
||||||
Opcodes.append({dwarf::DW_OP_constu, Val});
|
Opcodes.append({dwarf::DW_OP_constu, Val});
|
||||||
|
} else {
|
||||||
|
if (!CurrentLocOps) {
|
||||||
|
Opcodes.append({dwarf::DW_OP_LLVM_arg, 0});
|
||||||
|
CurrentLocOps = 1;
|
||||||
|
}
|
||||||
|
Opcodes.append({dwarf::DW_OP_LLVM_arg, CurrentLocOps});
|
||||||
|
AdditionalValues.push_back(BI->getOperand(1));
|
||||||
|
}
|
||||||
|
|
||||||
// Add salvaged binary operator to expression stack, if it has a valid
|
// Add salvaged binary operator to expression stack, if it has a valid
|
||||||
// representation in a DIExpression.
|
// representation in a DIExpression.
|
||||||
@ -1823,9 +1870,11 @@ bool getSalvageOpsForBinOp(BinaryOperator *BI,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
DIExpression *llvm::salvageDebugInfoImpl(Instruction &I,
|
DIExpression *
|
||||||
DIExpression *SrcDIExpr,
|
llvm::salvageDebugInfoImpl(Instruction &I, DIExpression *SrcDIExpr,
|
||||||
bool WithStackValue, unsigned LocNo) {
|
bool WithStackValue, unsigned LocNo,
|
||||||
|
SmallVectorImpl<Value *> &AdditionalValues) {
|
||||||
|
uint64_t CurrentLocOps = SrcDIExpr->getNumLocationOperands();
|
||||||
auto &M = *I.getModule();
|
auto &M = *I.getModule();
|
||||||
auto &DL = M.getDataLayout();
|
auto &DL = M.getDataLayout();
|
||||||
|
|
||||||
@ -1839,7 +1888,7 @@ DIExpression *llvm::salvageDebugInfoImpl(Instruction &I,
|
|||||||
};
|
};
|
||||||
|
|
||||||
// initializer-list helper for applying operators to the source DIExpression.
|
// initializer-list helper for applying operators to the source DIExpression.
|
||||||
auto applyOps = [&](ArrayRef<uint64_t> Opcodes) -> DIExpression * {
|
auto applyOps = [&](ArrayRef<uint64_t> Opcodes) {
|
||||||
SmallVector<uint64_t, 8> Ops(Opcodes.begin(), Opcodes.end());
|
SmallVector<uint64_t, 8> Ops(Opcodes.begin(), Opcodes.end());
|
||||||
return doSalvage(Ops);
|
return doSalvage(Ops);
|
||||||
};
|
};
|
||||||
@ -1865,10 +1914,10 @@ DIExpression *llvm::salvageDebugInfoImpl(Instruction &I,
|
|||||||
|
|
||||||
SmallVector<uint64_t, 8> Ops;
|
SmallVector<uint64_t, 8> Ops;
|
||||||
if (auto *GEP = dyn_cast<GetElementPtrInst>(&I)) {
|
if (auto *GEP = dyn_cast<GetElementPtrInst>(&I)) {
|
||||||
if (getSalvageOpsForGEP(GEP, DL, Ops))
|
if (getSalvageOpsForGEP(GEP, DL, CurrentLocOps, Ops, AdditionalValues))
|
||||||
return doSalvage(Ops);
|
return doSalvage(Ops);
|
||||||
} else if (auto *BI = dyn_cast<BinaryOperator>(&I)) {
|
} else if (auto *BI = dyn_cast<BinaryOperator>(&I)) {
|
||||||
if (getSalvageOpsForBinOp(BI, Ops))
|
if (getSalvageOpsForBinOp(BI, CurrentLocOps, Ops, AdditionalValues))
|
||||||
return doSalvage(Ops);
|
return doSalvage(Ops);
|
||||||
}
|
}
|
||||||
// *Not* to do: we should not attempt to salvage load instructions,
|
// *Not* to do: we should not attempt to salvage load instructions,
|
||||||
|
63
test/DebugInfo/limit-arglist-size.ll
Normal file
63
test/DebugInfo/limit-arglist-size.ll
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
; RUN: opt -S -instcombine %s -o - | FileCheck %s
|
||||||
|
|
||||||
|
; For performance reasons, we currently limit the number of values that can be
|
||||||
|
; referenced by a dbg.value to 16. This test checks that we do not exceed this
|
||||||
|
; limit during salvaging.
|
||||||
|
|
||||||
|
; CHECK: DIArgList(i32 undef
|
||||||
|
; CHECK-NOT: DW_OP_LLVM_arg, 16
|
||||||
|
|
||||||
|
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
|
||||||
|
target triple = "x86_64-unknown-linux-gnu"
|
||||||
|
|
||||||
|
define i32 @_Z3foov() local_unnamed_addr !dbg !9 {
|
||||||
|
entry:
|
||||||
|
%call = call i32 @_Z3barv(), !dbg !14
|
||||||
|
%call1 = call i32 @_Z3barv(), !dbg !14
|
||||||
|
%add = add nsw i32 %call, %call1, !dbg !14
|
||||||
|
%call2 = call i32 @_Z3barv(), !dbg !14
|
||||||
|
%call4 = call i32 @_Z3barv(), !dbg !14
|
||||||
|
%call6 = call i32 @_Z3barv(), !dbg !14
|
||||||
|
%call8 = call i32 @_Z3barv(), !dbg !14
|
||||||
|
%call10 = call i32 @_Z3barv(), !dbg !14
|
||||||
|
%call12 = call i32 @_Z3barv(), !dbg !14
|
||||||
|
%call14 = call i32 @_Z3barv(), !dbg !14
|
||||||
|
%call16 = call i32 @_Z3barv(), !dbg !14
|
||||||
|
%call18 = call i32 @_Z3barv(), !dbg !14
|
||||||
|
%call20 = call i32 @_Z3barv(), !dbg !14
|
||||||
|
%call22 = call i32 @_Z3barv(), !dbg !14
|
||||||
|
%call24 = call i32 @_Z3barv(), !dbg !14
|
||||||
|
%call26 = call i32 @_Z3barv(), !dbg !14
|
||||||
|
%call28 = call i32 @_Z3barv(), !dbg !14
|
||||||
|
%call30 = call i32 @_Z3barv(), !dbg !14
|
||||||
|
call void @llvm.dbg.value(metadata !DIArgList(i32 %add, i32 %call30, i32 %call28, i32 %call26, i32 %call24, i32 %call22, i32 %call20, i32 %call18, i32 %call16, i32 %call14, i32 %call12, i32 %call10, i32 %call8, i32 %call6, i32 %call4, i32 %call2), metadata !15, metadata !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_LLVM_arg, 15, DW_OP_plus, DW_OP_LLVM_arg, 14, DW_OP_plus, DW_OP_LLVM_arg, 13, DW_OP_plus, DW_OP_LLVM_arg, 12, DW_OP_plus, DW_OP_LLVM_arg, 11, DW_OP_plus, DW_OP_LLVM_arg, 10, DW_OP_plus, DW_OP_LLVM_arg, 9, DW_OP_plus, DW_OP_LLVM_arg, 8, DW_OP_plus, DW_OP_LLVM_arg, 7, DW_OP_plus, DW_OP_LLVM_arg, 6, DW_OP_plus, DW_OP_LLVM_arg, 5, DW_OP_plus, DW_OP_LLVM_arg, 4, DW_OP_plus, DW_OP_LLVM_arg, 3, DW_OP_plus, DW_OP_LLVM_arg, 2, DW_OP_plus, DW_OP_LLVM_arg, 1, DW_OP_plus, DW_OP_stack_value)), !dbg !16
|
||||||
|
%call32 = call i32 @_Z3barv(), !dbg !17
|
||||||
|
ret i32 %call32, !dbg !17
|
||||||
|
}
|
||||||
|
|
||||||
|
declare dso_local i32 @_Z3barv() local_unnamed_addr
|
||||||
|
|
||||||
|
declare void @llvm.dbg.value(metadata, metadata, metadata)
|
||||||
|
|
||||||
|
!llvm.dbg.cu = !{!0}
|
||||||
|
!llvm.module.flags = !{!3, !4, !5, !6, !7}
|
||||||
|
!llvm.ident = !{!8}
|
||||||
|
|
||||||
|
!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 13.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None)
|
||||||
|
!1 = !DIFile(filename: "limit-arglist-size.cpp", directory: "/")
|
||||||
|
!2 = !{}
|
||||||
|
!3 = !{i32 7, !"Dwarf Version", i32 4}
|
||||||
|
!4 = !{i32 2, !"Debug Info Version", i32 3}
|
||||||
|
!5 = !{i32 1, !"wchar_size", i32 4}
|
||||||
|
!6 = !{i32 7, !"uwtable", i32 1}
|
||||||
|
!7 = !{i32 7, !"frame-pointer", i32 2}
|
||||||
|
!8 = !{!"clang version 13.0.0"}
|
||||||
|
!9 = distinct !DISubprogram(name: "foo", linkageName: "_Z3foov", scope: !10, file: !10, line: 3, type: !11, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2)
|
||||||
|
!10 = !DIFile(filename: "./limit-arglist-size.cpp", directory: "/")
|
||||||
|
!11 = !DISubroutineType(types: !12)
|
||||||
|
!12 = !{!13}
|
||||||
|
!13 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
|
||||||
|
!14 = !DILocation(line: 4, scope: !9)
|
||||||
|
!15 = !DILocalVariable(name: "v16", scope: !9, file: !10, line: 4, type: !13)
|
||||||
|
!16 = !DILocation(line: 0, scope: !9)
|
||||||
|
!17 = !DILocation(line: 5, scope: !9)
|
57
test/DebugInfo/salvage-gep.ll
Normal file
57
test/DebugInfo/salvage-gep.ll
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
; XFAIL: *
|
||||||
|
; RUN: opt %s -dce -S | FileCheck %s
|
||||||
|
|
||||||
|
; Tests the salvaging of GEP instructions, specifically struct indexing and
|
||||||
|
; non-constant array indexing.
|
||||||
|
|
||||||
|
%struct.S = type { i32, i32 }
|
||||||
|
|
||||||
|
; CHECK: call void @llvm.dbg.value(metadata !DIArgList(%struct.S* %ptr, i64 %offset),
|
||||||
|
; CHECK-SAME: ![[VAR_OFFSET_PTR:[0-9]+]],
|
||||||
|
; CHECK-SAME: !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_LLVM_arg, 1, DW_OP_constu, 8, DW_OP_mul, DW_OP_plus, DW_OP_plus_uconst, 4, DW_OP_stack_value))
|
||||||
|
|
||||||
|
; CHECK: ![[VAR_OFFSET_PTR]] = !DILocalVariable(name: "offset_ptr"
|
||||||
|
|
||||||
|
define void @"?foo@@YAXPEAUS@@_J@Z"(%struct.S* %ptr, i64 %offset) !dbg !8 {
|
||||||
|
entry:
|
||||||
|
call void @llvm.dbg.value(metadata i64 %offset, metadata !20, metadata !DIExpression()), !dbg !24
|
||||||
|
call void @llvm.dbg.value(metadata %struct.S* %ptr, metadata !21, metadata !DIExpression()), !dbg !24
|
||||||
|
%arrayidx = getelementptr inbounds %struct.S, %struct.S* %ptr, i64 %offset, !dbg !25
|
||||||
|
%b = getelementptr inbounds %struct.S, %struct.S* %arrayidx, i32 0, i32 1, !dbg !25
|
||||||
|
call void @llvm.dbg.value(metadata i32* %b, metadata !22, metadata !DIExpression()), !dbg !24
|
||||||
|
ret void, !dbg !26
|
||||||
|
}
|
||||||
|
|
||||||
|
declare void @llvm.dbg.value(metadata, metadata, metadata)
|
||||||
|
|
||||||
|
!llvm.dbg.cu = !{!0}
|
||||||
|
!llvm.module.flags = !{!3, !4, !5, !6}
|
||||||
|
!llvm.ident = !{!7}
|
||||||
|
|
||||||
|
!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 11.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None)
|
||||||
|
!1 = !DIFile(filename: "salvage-gep.cpp", directory: "/")
|
||||||
|
!2 = !{}
|
||||||
|
!3 = !{i32 2, !"CodeView", i32 1}
|
||||||
|
!4 = !{i32 2, !"Debug Info Version", i32 3}
|
||||||
|
!5 = !{i32 1, !"wchar_size", i32 2}
|
||||||
|
!6 = !{i32 7, !"PIC Level", i32 2}
|
||||||
|
!7 = !{!"clang version 11.0.0"}
|
||||||
|
!8 = distinct !DISubprogram(name: "foo", linkageName: "?foo@@YAXPEAUS@@_J@Z", scope: !9, file: !9, line: 7, type: !10, scopeLine: 7, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !19)
|
||||||
|
!9 = !DIFile(filename: ".\\salvage-gep.cpp", directory: "/")
|
||||||
|
!10 = !DISubroutineType(types: !11)
|
||||||
|
!11 = !{null, !12, !18}
|
||||||
|
!12 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !13, size: 64)
|
||||||
|
!13 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "S", file: !9, line: 2, size: 64, flags: DIFlagTypePassByValue, elements: !14, identifier: ".?AUS@@")
|
||||||
|
!14 = !{!15, !17}
|
||||||
|
!15 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !13, file: !9, line: 3, baseType: !16, size: 32)
|
||||||
|
!16 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
|
||||||
|
!17 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !13, file: !9, line: 4, baseType: !16, size: 32, offset: 32)
|
||||||
|
!18 = !DIBasicType(name: "long long int", size: 64, encoding: DW_ATE_signed)
|
||||||
|
!19 = !{!20, !21, !22}
|
||||||
|
!20 = !DILocalVariable(name: "offset", arg: 2, scope: !8, file: !9, line: 7, type: !18)
|
||||||
|
!21 = !DILocalVariable(name: "ptr", arg: 1, scope: !8, file: !9, line: 7, type: !12)
|
||||||
|
!22 = !DILocalVariable(name: "offset_ptr", scope: !8, file: !9, line: 8, type: !23)
|
||||||
|
!23 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !16, size: 64)
|
||||||
|
!24 = !DILocation(line: 0, scope: !8)
|
||||||
|
!25 = !DILocation(line: 8, scope: !8)
|
||||||
|
!26 = !DILocation(line: 9, scope: !8)
|
46
test/DebugInfo/salvage-nonconst-binop.ll
Normal file
46
test/DebugInfo/salvage-nonconst-binop.ll
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
; XFAIL: *
|
||||||
|
; RUN: opt %s -dce -S | FileCheck %s
|
||||||
|
|
||||||
|
; Tests the salvaging of binary operators that use more than one non-constant
|
||||||
|
; SSA value.
|
||||||
|
|
||||||
|
; CHECK: call void @llvm.dbg.value(metadata !DIArgList(i32 %a, i32 %b),
|
||||||
|
; CHECK-SAME: ![[VAR_C:[0-9]+]],
|
||||||
|
; CHECK-SAME: !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_LLVM_arg, 1, DW_OP_plus, DW_OP_stack_value))
|
||||||
|
|
||||||
|
; CHECK: ![[VAR_C]] = !DILocalVariable(name: "c"
|
||||||
|
|
||||||
|
define i32 @"?multiply@@YAHHH@Z"(i32 %a, i32 %b) !dbg !8 {
|
||||||
|
entry:
|
||||||
|
call void @llvm.dbg.value(metadata i32 %b, metadata !12, metadata !DIExpression()), !dbg !13
|
||||||
|
call void @llvm.dbg.value(metadata i32 %a, metadata !14, metadata !DIExpression()), !dbg !13
|
||||||
|
%add = add nsw i32 %a, %b, !dbg !15
|
||||||
|
call void @llvm.dbg.value(metadata i32 %add, metadata !16, metadata !DIExpression()), !dbg !13
|
||||||
|
%mul = mul nsw i32 %a, %b, !dbg !17
|
||||||
|
ret i32 %mul, !dbg !17
|
||||||
|
}
|
||||||
|
|
||||||
|
declare void @llvm.dbg.value(metadata, metadata, metadata)
|
||||||
|
|
||||||
|
!llvm.dbg.cu = !{!0}
|
||||||
|
!llvm.module.flags = !{!3, !4, !5, !6}
|
||||||
|
!llvm.ident = !{!7}
|
||||||
|
|
||||||
|
!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 11.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None)
|
||||||
|
!1 = !DIFile(filename: "test.cpp", directory: "/")
|
||||||
|
!2 = !{}
|
||||||
|
!3 = !{i32 2, !"CodeView", i32 1}
|
||||||
|
!4 = !{i32 2, !"Debug Info Version", i32 3}
|
||||||
|
!5 = !{i32 1, !"wchar_size", i32 2}
|
||||||
|
!6 = !{i32 7, !"PIC Level", i32 2}
|
||||||
|
!7 = !{!"clang version 11.0.0"}
|
||||||
|
!8 = distinct !DISubprogram(name: "multiply", linkageName: "?multiply@@YAHHH@Z", scope: !1, file: !1, line: 1, type: !9, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2)
|
||||||
|
!9 = !DISubroutineType(types: !10)
|
||||||
|
!10 = !{!11, !11, !11}
|
||||||
|
!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
|
||||||
|
!12 = !DILocalVariable(name: "b", arg: 2, scope: !8, file: !1, line: 1, type: !11)
|
||||||
|
!13 = !DILocation(line: 0, scope: !8)
|
||||||
|
!14 = !DILocalVariable(name: "a", arg: 1, scope: !8, file: !1, line: 1, type: !11)
|
||||||
|
!15 = !DILocation(line: 2, scope: !8)
|
||||||
|
!16 = !DILocalVariable(name: "c", scope: !8, file: !1, line: 2, type: !11)
|
||||||
|
!17 = !DILocation(line: 3, scope: !8)
|
@ -33,23 +33,25 @@ sink1:
|
|||||||
; value range.
|
; value range.
|
||||||
|
|
||||||
; CHECK-LABEL: define i32 @bar(
|
; CHECK-LABEL: define i32 @bar(
|
||||||
; CHECK: call void @llvm.dbg.value(metadata i32* undef,
|
; CHECK: call void @llvm.dbg.value(metadata <vscale x 4 x i32>* undef,
|
||||||
; CHECK-NEXT: br label %sink2
|
; CHECK-NEXT: br label %sink2
|
||||||
|
|
||||||
define i32 @bar(i32 *%a, i32 %b) !dbg !70 {
|
define i32 @bar(<vscale x 4 x i32>* %a, i32 %b) !dbg !70 {
|
||||||
entry:
|
entry:
|
||||||
%gep = getelementptr i32, i32 *%a, i32 %b
|
%gep = getelementptr <vscale x 4 x i32>, <vscale x 4 x i32>* %a, i32 %b
|
||||||
call void @llvm.dbg.value(metadata i32* %gep, metadata !73, metadata !12), !dbg !74
|
call void @llvm.dbg.value(metadata <vscale x 4 x i32>* %gep, metadata !73, metadata !12), !dbg !74
|
||||||
br label %sink2
|
br label %sink2
|
||||||
|
|
||||||
sink2:
|
sink2:
|
||||||
; CHECK-LABEL: sink2:
|
; CHECK-LABEL: sink2:
|
||||||
; CHECK: call void @llvm.dbg.value(metadata i32* %gep,
|
; CHECK: call void @llvm.dbg.value(metadata <vscale x 4 x i32>* %gep,
|
||||||
; CHECK-SAME: metadata !{{[0-9]+}}, metadata !DIExpression())
|
; CHECK-SAME: metadata !{{[0-9]+}}, metadata !DIExpression())
|
||||||
; CHECK-NEXT: load
|
; CHECK-NEXT: load
|
||||||
|
; CHECK-NEXT: extractelement
|
||||||
; CHECK-NEXT: ret
|
; CHECK-NEXT: ret
|
||||||
%0 = load i32, i32* %gep
|
%0 = load <vscale x 4 x i32>, <vscale x 4 x i32>* %gep
|
||||||
ret i32 %0
|
%extract = extractelement <vscale x 4 x i32> %0, i32 1
|
||||||
|
ret i32 %extract
|
||||||
}
|
}
|
||||||
|
|
||||||
; This GEP is sunk, and has multiple debug uses in the same block. Check that
|
; This GEP is sunk, and has multiple debug uses in the same block. Check that
|
||||||
|
@ -3,93 +3,71 @@
|
|||||||
; Check that reassociate pass now undefs debug intrinsics that reference a value
|
; Check that reassociate pass now undefs debug intrinsics that reference a value
|
||||||
; that gets dropped and cannot be salvaged.
|
; that gets dropped and cannot be salvaged.
|
||||||
|
|
||||||
define hidden i32 @main() local_unnamed_addr {
|
; CHECK-NOT: %add = fadd fast float %a, %b
|
||||||
entry:
|
; CHECK: call void @llvm.dbg.value(metadata float undef, metadata [[VAR_X:![0-9]+]], metadata !DIExpression())
|
||||||
%foo = alloca i32, align 4, !dbg !20
|
|
||||||
%foo.0.foo.0..sroa_cast = bitcast i32* %foo to i8*, !dbg !20
|
|
||||||
call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %foo.0.foo.0..sroa_cast), !dbg !20
|
|
||||||
store volatile i32 4, i32* %foo, align 4, !dbg !20, !tbaa !21
|
|
||||||
%foo.0.foo.0. = load volatile i32, i32* %foo, align 4, !dbg !25, !tbaa !21
|
|
||||||
%foo.0.foo.0.15 = load volatile i32, i32* %foo, align 4, !dbg !27, !tbaa !21
|
|
||||||
%foo.0.foo.0.16 = load volatile i32, i32* %foo, align 4, !dbg !28, !tbaa !21
|
|
||||||
; CHECK-NOT: %add = add nsw i32 %foo.0.foo.0., %foo.0.foo.0.15
|
|
||||||
%add = add nsw i32 %foo.0.foo.0., %foo.0.foo.0.15, !dbg !29
|
|
||||||
; CHECK: call void @llvm.dbg.value(metadata i32 undef, metadata [[VAR_A:![0-9]+]], metadata !DIExpression())
|
|
||||||
call void @llvm.dbg.value(metadata i32 %add, metadata !19, metadata !DIExpression()), !dbg !26
|
|
||||||
%foo.0.foo.0.17 = load volatile i32, i32* %foo, align 4, !dbg !30, !tbaa !21
|
|
||||||
%cmp = icmp eq i32 %foo.0.foo.0.17, 4, !dbg !30
|
|
||||||
br i1 %cmp, label %if.then, label %if.end, !dbg !32
|
|
||||||
|
|
||||||
; CHECK-LABEL: if.then:
|
; CHECK-LABEL: if.then:
|
||||||
if.then:
|
; CHECK-NOT: %add1 = fadd fast float %add, %c
|
||||||
; CHECK-NOT: %add1 = add nsw i32 %add, %foo.0.foo.0.16
|
; CHECK: call void @llvm.dbg.value(metadata float undef, metadata [[VAR_Y:![0-9]+]], metadata !DIExpression())
|
||||||
%add1 = add nsw i32 %add, %foo.0.foo.0.16, !dbg !33
|
; CHECK-LABEL: !0 =
|
||||||
; CHECK: call void @llvm.dbg.value(metadata i32 undef, metadata [[VAR_A]], metadata !DIExpression())
|
; CHECK-DAG: [[VAR_Y]] = !DILocalVariable(name: "y"
|
||||||
call void @llvm.dbg.value(metadata i32 %add1, metadata !19, metadata !DIExpression()), !dbg !26
|
; CHECK-DAG: [[VAR_X]] = !DILocalVariable(name: "x"
|
||||||
; CHECK: call void @llvm.dbg.value(metadata i32 undef, metadata [[VAR_CHEESE:![0-9]+]], metadata !DIExpression())
|
|
||||||
call void @llvm.dbg.value(metadata i32 %add, metadata !18, metadata !DIExpression()), !dbg !26
|
|
||||||
%sub = add nsw i32 %add, -12, !dbg !34
|
|
||||||
%sub3 = sub nsw i32 %add1, %sub, !dbg !34
|
|
||||||
%mul = mul nsw i32 %sub3, 20, !dbg !36
|
|
||||||
%div = sdiv i32 %mul, 3, !dbg !37
|
|
||||||
br label %if.end, !dbg !38
|
|
||||||
|
|
||||||
if.end:
|
define float @"?foo@@YAMMMMM@Z"(float %a, float %b, float %c, float %d) !dbg !8 {
|
||||||
%a.0 = phi i32 [ %div, %if.then ], [ 0, %entry ], !dbg !39
|
entry:
|
||||||
call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %foo.0.foo.0..sroa_cast), !dbg !40
|
call void @llvm.dbg.value(metadata float %d, metadata !12, metadata !DIExpression()), !dbg !13
|
||||||
ret i32 %a.0, !dbg !41
|
call void @llvm.dbg.value(metadata float %c, metadata !14, metadata !DIExpression()), !dbg !13
|
||||||
|
call void @llvm.dbg.value(metadata float %b, metadata !15, metadata !DIExpression()), !dbg !13
|
||||||
|
call void @llvm.dbg.value(metadata float %a, metadata !16, metadata !DIExpression()), !dbg !13
|
||||||
|
%add = fadd fast float %a, %b, !dbg !17
|
||||||
|
call void @llvm.dbg.value(metadata float %add, metadata !18, metadata !DIExpression()), !dbg !13
|
||||||
|
%cmp = fcmp fast oeq float %d, 4.000000e+00, !dbg !19
|
||||||
|
br i1 %cmp, label %if.then, label %return, !dbg !19
|
||||||
|
|
||||||
|
if.then: ; preds = %entry
|
||||||
|
%add1 = fadd fast float %add, %c, !dbg !20
|
||||||
|
call void @llvm.dbg.value(metadata float %add1, metadata !23, metadata !DIExpression()), !dbg !24
|
||||||
|
%sub = fsub fast float %add, 1.200000e+01, !dbg !25
|
||||||
|
%sub2 = fsub fast float %add1, %sub, !dbg !25
|
||||||
|
%mul = fmul fast float %sub2, 2.000000e+01, !dbg !25
|
||||||
|
%div = fdiv fast float %mul, 3.000000e+00, !dbg !25
|
||||||
|
br label %return, !dbg !25
|
||||||
|
|
||||||
|
return: ; preds = %entry, %if.then
|
||||||
|
%retval.0 = phi float [ %div, %if.then ], [ 0.000000e+00, %entry ], !dbg !13
|
||||||
|
ret float %retval.0, !dbg !26
|
||||||
}
|
}
|
||||||
|
|
||||||
declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #1
|
declare void @llvm.dbg.value(metadata, metadata, metadata)
|
||||||
declare void @llvm.dbg.declare(metadata, metadata, metadata) #2
|
|
||||||
declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture) #1
|
|
||||||
declare void @llvm.dbg.value(metadata, metadata, metadata) #2
|
|
||||||
|
|
||||||
!llvm.dbg.cu = !{!0}
|
!llvm.dbg.cu = !{!0}
|
||||||
!llvm.module.flags = !{!3, !4, !5, !6}
|
!llvm.module.flags = !{!3, !4, !5, !6}
|
||||||
!llvm.ident = !{!7}
|
!llvm.ident = !{!7}
|
||||||
|
|
||||||
!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 10.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, debugInfoForProfiling: true, nameTableKind: None)
|
!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 11.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None)
|
||||||
!1 = !DIFile(filename: "test.cpp", directory: "F:\")
|
!1 = !DIFile(filename: "undef_intrinsics_when_deleting_instructions.cpp", directory: "/")
|
||||||
!2 = !{}
|
!2 = !{}
|
||||||
!3 = !{i32 2, !"Dwarf Version", i32 4}
|
!3 = !{i32 2, !"CodeView", i32 1}
|
||||||
!4 = !{i32 2, !"Debug Info Version", i32 3}
|
!4 = !{i32 2, !"Debug Info Version", i32 3}
|
||||||
!5 = !{i32 1, !"wchar_size", i32 2}
|
!5 = !{i32 1, !"wchar_size", i32 2}
|
||||||
!6 = !{i32 7, !"PIC Level", i32 2}
|
!6 = !{i32 7, !"PIC Level", i32 2}
|
||||||
!7 = !{!"clang version 10.0.0"}
|
!7 = !{!"clang version 11.0.0"}
|
||||||
!8 = distinct !DISubprogram(name: "main", scope: !9, file: !9, line: 1, type: !10, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !13)
|
!8 = distinct !DISubprogram(name: "foo", linkageName: "?foo@@YAMMMMM@Z", scope: !1, file: !1, line: 1, type: !9, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2)
|
||||||
!9 = !DIFile(filename: "./test.cpp", directory: "F:\")
|
!9 = !DISubroutineType(types: !10)
|
||||||
!10 = !DISubroutineType(types: !11)
|
!10 = !{!11, !11, !11, !11, !11}
|
||||||
!11 = !{!12}
|
!11 = !DIBasicType(name: "float", size: 32, encoding: DW_ATE_float)
|
||||||
!12 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
|
!12 = !DILocalVariable(name: "d", arg: 4, scope: !8, file: !1, line: 1, type: !11)
|
||||||
!13 = !{!14, !16, !17, !18, !19}
|
!13 = !DILocation(line: 0, scope: !8)
|
||||||
!14 = !DILocalVariable(name: "foo", scope: !8, file: !9, line: 2, type: !15)
|
!14 = !DILocalVariable(name: "c", arg: 3, scope: !8, file: !1, line: 1, type: !11)
|
||||||
!15 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !12)
|
!15 = !DILocalVariable(name: "b", arg: 2, scope: !8, file: !1, line: 1, type: !11)
|
||||||
!16 = !DILocalVariable(name: "read1", scope: !8, file: !9, line: 3, type: !12)
|
!16 = !DILocalVariable(name: "a", arg: 1, scope: !8, file: !1, line: 1, type: !11)
|
||||||
!17 = !DILocalVariable(name: "read2", scope: !8, file: !9, line: 4, type: !12)
|
!17 = !DILocation(line: 2, scope: !8)
|
||||||
; CHECK: [[VAR_CHEESE]] = !DILocalVariable(name: "cheese"
|
!18 = !DILocalVariable(name: "x", scope: !8, file: !1, line: 2, type: !11)
|
||||||
!18 = !DILocalVariable(name: "cheese", scope: !8, file: !9, line: 6, type: !12)
|
!19 = !DILocation(line: 3, scope: !8)
|
||||||
; CHECK: [[VAR_A]] = !DILocalVariable(name: "a"
|
!20 = !DILocation(line: 4, scope: !21)
|
||||||
!19 = !DILocalVariable(name: "a", scope: !8, file: !9, line: 7, type: !12)
|
!21 = distinct !DILexicalBlock(scope: !22, file: !1, line: 3)
|
||||||
!20 = !DILocation(line: 2, scope: !8)
|
!22 = distinct !DILexicalBlock(scope: !8, file: !1, line: 3)
|
||||||
!21 = !{!22, !22, i64 0}
|
!23 = !DILocalVariable(name: "y", scope: !21, file: !1, line: 4, type: !11)
|
||||||
!22 = !{!"int", !23, i64 0}
|
!24 = !DILocation(line: 0, scope: !21)
|
||||||
!23 = !{!"omnipotent char", !24, i64 0}
|
!25 = !DILocation(line: 5, scope: !21)
|
||||||
!24 = !{!"Simple C++ TBAA"}
|
!26 = !DILocation(line: 8, scope: !8)
|
||||||
!25 = !DILocation(line: 3, scope: !8)
|
|
||||||
!26 = !DILocation(line: 0, scope: !8)
|
|
||||||
!27 = !DILocation(line: 4, scope: !8)
|
|
||||||
!28 = !DILocation(line: 6, scope: !8)
|
|
||||||
!29 = !DILocation(line: 7, scope: !8)
|
|
||||||
!30 = !DILocation(line: 10, scope: !31)
|
|
||||||
!31 = distinct !DILexicalBlock(scope: !8, file: !9, line: 10)
|
|
||||||
!32 = !DILocation(line: 10, scope: !8)
|
|
||||||
!33 = !DILocation(line: 8, scope: !8)
|
|
||||||
!34 = !DILocation(line: 12, scope: !35)
|
|
||||||
!35 = distinct !DILexicalBlock(scope: !31, file: !9, line: 10)
|
|
||||||
!36 = !DILocation(line: 13, scope: !35)
|
|
||||||
!37 = !DILocation(line: 14, scope: !35)
|
|
||||||
!38 = !DILocation(line: 15, scope: !35)
|
|
||||||
!39 = !DILocation(line: 0, scope: !31)
|
|
||||||
!40 = !DILocation(line: 20, scope: !8)
|
|
||||||
!41 = !DILocation(line: 19, scope: !8)
|
|
||||||
|
Loading…
Reference in New Issue
Block a user