forked from OSchip/llvm-project
Re-land r313825: "[IR] Add llvm.dbg.addr, a control-dependent version of llvm.dbg.declare"
The fix is to avoid invalidating our insertion point in replaceDbgDeclare: Builder.insertDeclare(NewAddress, DIVar, DIExpr, Loc, InsertBefore); + if (DII == InsertBefore) + InsertBefore = &*std::next(InsertBefore->getIterator()); DII->eraseFromParent(); I had to write a unit tests for this instead of a lit test because the use list order matters in order to trigger the bug. The reduced C test case for this was: void useit(int*); static inline void inlineme() { int x[2]; useit(x); } void f() { inlineme(); inlineme(); } llvm-svn: 313905
This commit is contained in:
parent
977996d25b
commit
0fe506bc5e
|
@ -171,7 +171,48 @@ Debugger intrinsic functions
|
|||
----------------------------
|
||||
|
||||
LLVM uses several intrinsic functions (name prefixed with "``llvm.dbg``") to
|
||||
provide debug information at various points in generated code.
|
||||
track source local variables through optimization and code generation.
|
||||
|
||||
``llvm.dbg.addr``
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. code-block:: llvm
|
||||
|
||||
void @llvm.dbg.addr(metadata, metadata, metadata)
|
||||
|
||||
This intrinsic provides information about a local element (e.g., variable).
|
||||
The first argument is metadata holding the address of variable, typically a
|
||||
static alloca in the function entry block. The second argument is a
|
||||
`local variable <LangRef.html#dilocalvariable>`_ containing a description of
|
||||
the variable. The third argument is a `complex expression
|
||||
<LangRef.html#diexpression>`_. An `llvm.dbg.addr` intrinsic describes the
|
||||
*address* of a source variable.
|
||||
|
||||
.. code-block:: llvm
|
||||
|
||||
%i.addr = alloca i32, align 4
|
||||
call void @llvm.dbg.addr(metadata i32* %i.addr, metadata !1,
|
||||
metadata !DIExpression()), !dbg !2
|
||||
!1 = !DILocalVariable(name: "i", ...) ; int i
|
||||
!2 = !DILocation(...)
|
||||
...
|
||||
%buffer = alloca [256 x i8], align 8
|
||||
; The address of i is buffer+64.
|
||||
call void @llvm.dbg.addr(metadata [256 x i8]* %buffer, metadata !3,
|
||||
metadata !DIExpression(DW_OP_plus, 64)), !dbg !4
|
||||
!3 = !DILocalVariable(name: "i", ...) ; int i
|
||||
!4 = !DILocation(...)
|
||||
|
||||
A frontend should generate exactly one call to ``llvm.dbg.addr`` at the point
|
||||
of declaration of a source variable. Optimization passes that fully promote the
|
||||
variable from memory to SSA values will replace this call with possibly
|
||||
multiple calls to `llvm.dbg.value`. Passes that delete stores are effectively
|
||||
partial promotion, and they will insert a mix of calls to ``llvm.dbg.value``
|
||||
and ``llvm.dbg.addr`` to track the source variable value when it is available.
|
||||
After optimization, there may be multiple calls to ``llvm.dbg.addr`` describing
|
||||
the program points where the variables lives in memory. All calls for the same
|
||||
concrete source variable must agree on the memory location.
|
||||
|
||||
|
||||
``llvm.dbg.declare``
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -180,26 +221,14 @@ provide debug information at various points in generated code.
|
|||
|
||||
void @llvm.dbg.declare(metadata, metadata, metadata)
|
||||
|
||||
This intrinsic provides information about a local element (e.g., variable). The
|
||||
first argument is metadata holding the alloca for the variable. The second
|
||||
argument is a `local variable <LangRef.html#dilocalvariable>`_ containing a
|
||||
description of the variable. The third argument is a `complex expression
|
||||
<LangRef.html#diexpression>`_. An `llvm.dbg.declare` instrinsic describes the
|
||||
*location* of a source variable.
|
||||
|
||||
.. code-block:: llvm
|
||||
|
||||
%i.addr = alloca i32, align 4
|
||||
call void @llvm.dbg.declare(metadata i32* %i.addr, metadata !1, metadata !2), !dbg !3
|
||||
!1 = !DILocalVariable(name: "i", ...) ; int i
|
||||
!2 = !DIExpression()
|
||||
!3 = !DILocation(...)
|
||||
...
|
||||
%buffer = alloca [256 x i8], align 8
|
||||
; The address of i is buffer+64.
|
||||
call void @llvm.dbg.declare(metadata [256 x i8]* %buffer, metadata !1, metadata !2)
|
||||
!1 = !DILocalVariable(name: "i", ...) ; int i
|
||||
!2 = !DIExpression(DW_OP_plus, 64)
|
||||
This intrinsic is identical to `llvm.dbg.addr`, except that there can only be
|
||||
one call to `llvm.dbg.declare` for a given concrete `local variable
|
||||
<LangRef.html#dilocalvariable>`_. It is not control-dependent, meaning that if
|
||||
a call to `llvm.dbg.declare` exists and has a valid location argument, that
|
||||
address is considered to be the true home of the variable across its entire
|
||||
lifetime. This makes it hard for optimizations to preserve accurate debug info
|
||||
in the presence of ``llvm.dbg.declare``, so we are transitioning away from it,
|
||||
and we plan to deprecate it in future LLVM releases.
|
||||
|
||||
|
||||
``llvm.dbg.value``
|
||||
|
@ -242,6 +271,9 @@ following C fragment, for example:
|
|||
8. X = Y;
|
||||
9. }
|
||||
|
||||
.. FIXME: Update the following example to use llvm.dbg.addr once that is the
|
||||
default in clang.
|
||||
|
||||
Compiled to LLVM, this function would be represented like this:
|
||||
|
||||
.. code-block:: text
|
||||
|
|
|
@ -71,6 +71,12 @@ namespace llvm {
|
|||
/// variable's value or its address.
|
||||
Value *getVariableLocation(bool AllowNullOp = true) const;
|
||||
|
||||
/// 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 getIntrinsicID() != Intrinsic::dbg_value;
|
||||
}
|
||||
|
||||
DILocalVariable *getVariable() const {
|
||||
return cast<DILocalVariable>(getRawVariable());
|
||||
}
|
||||
|
@ -87,11 +93,13 @@ namespace llvm {
|
|||
return cast<MetadataAsValue>(getArgOperand(2))->getMetadata();
|
||||
}
|
||||
|
||||
// Methods for support type inquiry through isa, cast, and dyn_cast:
|
||||
/// \name Casting methods
|
||||
/// @{
|
||||
static bool classof(const IntrinsicInst *I) {
|
||||
switch (I->getIntrinsicID()) {
|
||||
case Intrinsic::dbg_declare:
|
||||
case Intrinsic::dbg_value:
|
||||
case Intrinsic::dbg_addr:
|
||||
return true;
|
||||
default: return false;
|
||||
}
|
||||
|
@ -99,6 +107,7 @@ namespace llvm {
|
|||
static bool classof(const Value *V) {
|
||||
return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
|
||||
}
|
||||
/// @}
|
||||
};
|
||||
|
||||
/// This represents the llvm.dbg.declare instruction.
|
||||
|
@ -106,13 +115,30 @@ namespace llvm {
|
|||
public:
|
||||
Value *getAddress() const { return getVariableLocation(); }
|
||||
|
||||
// Methods for support type inquiry through isa, cast, and dyn_cast:
|
||||
/// \name Casting methods
|
||||
/// @{
|
||||
static bool classof(const IntrinsicInst *I) {
|
||||
return I->getIntrinsicID() == Intrinsic::dbg_declare;
|
||||
}
|
||||
static bool classof(const Value *V) {
|
||||
return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
|
||||
}
|
||||
/// @}
|
||||
};
|
||||
|
||||
/// This represents the llvm.dbg.addr instruction.
|
||||
class DbgAddrIntrinsic : public DbgInfoIntrinsic {
|
||||
public:
|
||||
Value *getAddress() const { return getVariableLocation(); }
|
||||
|
||||
/// \name Casting methods
|
||||
/// @{
|
||||
static bool classof(const IntrinsicInst *I) {
|
||||
return I->getIntrinsicID() == Intrinsic::dbg_addr;
|
||||
}
|
||||
static bool classof(const Value *V) {
|
||||
return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
|
||||
}
|
||||
};
|
||||
|
||||
/// This represents the llvm.dbg.value instruction.
|
||||
|
@ -122,13 +148,15 @@ namespace llvm {
|
|||
return getVariableLocation(/* AllowNullOp = */ false);
|
||||
}
|
||||
|
||||
// Methods for support type inquiry through isa, cast, and dyn_cast:
|
||||
/// \name Casting methods
|
||||
/// @{
|
||||
static bool classof(const IntrinsicInst *I) {
|
||||
return I->getIntrinsicID() == Intrinsic::dbg_value;
|
||||
}
|
||||
static bool classof(const Value *V) {
|
||||
return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
|
||||
}
|
||||
/// @}
|
||||
};
|
||||
|
||||
/// This is the common base class for constrained floating point intrinsics.
|
||||
|
|
|
@ -583,12 +583,16 @@ let IntrProperties = [IntrNoMem, IntrSpeculatable] in {
|
|||
let IntrProperties = [IntrNoMem, IntrSpeculatable] in {
|
||||
def int_dbg_declare : Intrinsic<[],
|
||||
[llvm_metadata_ty,
|
||||
llvm_metadata_ty,
|
||||
llvm_metadata_ty]>;
|
||||
llvm_metadata_ty,
|
||||
llvm_metadata_ty]>;
|
||||
def int_dbg_value : Intrinsic<[],
|
||||
[llvm_metadata_ty,
|
||||
llvm_metadata_ty,
|
||||
llvm_metadata_ty]>;
|
||||
def int_dbg_addr : Intrinsic<[],
|
||||
[llvm_metadata_ty,
|
||||
llvm_metadata_ty,
|
||||
llvm_metadata_ty]>;
|
||||
}
|
||||
|
||||
//===------------------ Exception Handling Intrinsics----------------------===//
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#define LLVM_TRANSFORMS_UTILS_LOCAL_H
|
||||
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/ADT/TinyPtrVector.h"
|
||||
#include "llvm/Analysis/AliasAnalysis.h"
|
||||
#include "llvm/IR/DataLayout.h"
|
||||
#include "llvm/IR/Dominators.h"
|
||||
|
@ -32,6 +33,7 @@ class BranchInst;
|
|||
class Instruction;
|
||||
class CallInst;
|
||||
class DbgDeclareInst;
|
||||
class DbgInfoIntrinsic;
|
||||
class DbgValueInst;
|
||||
class StoreInst;
|
||||
class LoadInst;
|
||||
|
@ -262,26 +264,28 @@ Value *EmitGEPOffset(IRBuilderTy *Builder, const DataLayout &DL, User *GEP,
|
|||
///
|
||||
|
||||
/// Inserts a llvm.dbg.value intrinsic before a store to an alloca'd value
|
||||
/// that has an associated llvm.dbg.decl intrinsic.
|
||||
void ConvertDebugDeclareToDebugValue(DbgDeclareInst *DDI,
|
||||
/// that has an associated llvm.dbg.declare or llvm.dbg.addr intrinsic.
|
||||
void ConvertDebugDeclareToDebugValue(DbgInfoIntrinsic *DII,
|
||||
StoreInst *SI, DIBuilder &Builder);
|
||||
|
||||
/// Inserts a llvm.dbg.value intrinsic before a load of an alloca'd value
|
||||
/// that has an associated llvm.dbg.decl intrinsic.
|
||||
void ConvertDebugDeclareToDebugValue(DbgDeclareInst *DDI,
|
||||
/// that has an associated llvm.dbg.declare or llvm.dbg.addr intrinsic.
|
||||
void ConvertDebugDeclareToDebugValue(DbgInfoIntrinsic *DII,
|
||||
LoadInst *LI, DIBuilder &Builder);
|
||||
|
||||
/// Inserts a llvm.dbg.value intrinsic after a phi of an alloca'd value
|
||||
/// that has an associated llvm.dbg.decl intrinsic.
|
||||
void ConvertDebugDeclareToDebugValue(DbgDeclareInst *DDI,
|
||||
/// Inserts a llvm.dbg.value intrinsic after a phi that has an associated
|
||||
/// llvm.dbg.declare or llvm.dbg.addr intrinsic.
|
||||
void ConvertDebugDeclareToDebugValue(DbgInfoIntrinsic *DII,
|
||||
PHINode *LI, DIBuilder &Builder);
|
||||
|
||||
/// Lowers llvm.dbg.declare intrinsics into appropriate set of
|
||||
/// llvm.dbg.value intrinsics.
|
||||
bool LowerDbgDeclare(Function &F);
|
||||
|
||||
/// Finds the llvm.dbg.declare intrinsic corresponding to an alloca, if any.
|
||||
DbgDeclareInst *FindAllocaDbgDeclare(Value *V);
|
||||
/// Finds all intrinsics declaring local variables as living in the memory that
|
||||
/// 'V' points to. This may include a mix of dbg.declare and
|
||||
/// dbg.addr intrinsics.
|
||||
TinyPtrVector<DbgInfoIntrinsic *> FindDbgAddrUses(Value *V);
|
||||
|
||||
/// Finds the llvm.dbg.value intrinsics describing a value.
|
||||
void findDbgValues(SmallVectorImpl<DbgValueInst *> &DbgValues, Value *V);
|
||||
|
|
|
@ -5109,37 +5109,48 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) {
|
|||
DAG.setRoot(CallResult.second);
|
||||
return nullptr;
|
||||
}
|
||||
case Intrinsic::dbg_addr:
|
||||
case Intrinsic::dbg_declare: {
|
||||
const DbgDeclareInst &DI = cast<DbgDeclareInst>(I);
|
||||
const DbgInfoIntrinsic &DI = cast<DbgInfoIntrinsic>(I);
|
||||
DILocalVariable *Variable = DI.getVariable();
|
||||
DIExpression *Expression = DI.getExpression();
|
||||
const Value *Address = DI.getAddress();
|
||||
assert(Variable && "Missing variable");
|
||||
if (!Address) {
|
||||
DEBUG(dbgs() << "Dropping debug info for " << DI << "\n");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Check if address has undef value.
|
||||
if (isa<UndefValue>(Address) ||
|
||||
const Value *Address = DI.getVariableLocation();
|
||||
if (!Address || isa<UndefValue>(Address) ||
|
||||
(Address->use_empty() && !isa<Argument>(Address))) {
|
||||
DEBUG(dbgs() << "Dropping debug info for " << DI << "\n");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Static allocas are handled more efficiently in the variable frame index
|
||||
// side table.
|
||||
if (const auto *AI =
|
||||
dyn_cast<AllocaInst>(Address->stripInBoundsConstantOffsets()))
|
||||
if (AI->isStaticAlloca() && FuncInfo.StaticAllocaMap.count(AI))
|
||||
return nullptr;
|
||||
bool isParameter = Variable->isParameter() || isa<Argument>(Address);
|
||||
|
||||
// Byval arguments with frame indices were already handled after argument
|
||||
// lowering and before isel.
|
||||
if (const auto *Arg =
|
||||
dyn_cast<Argument>(Address->stripInBoundsConstantOffsets()))
|
||||
if (FuncInfo.getArgumentFrameIndex(Arg) != INT_MAX)
|
||||
return nullptr;
|
||||
// Check if this variable can be described by a frame index, typically
|
||||
// either as a static alloca or a byval parameter.
|
||||
int FI = INT_MAX;
|
||||
if (const auto *AI =
|
||||
dyn_cast<AllocaInst>(Address->stripInBoundsConstantOffsets())) {
|
||||
if (AI->isStaticAlloca()) {
|
||||
auto I = FuncInfo.StaticAllocaMap.find(AI);
|
||||
if (I != FuncInfo.StaticAllocaMap.end())
|
||||
FI = I->second;
|
||||
}
|
||||
} else if (const auto *Arg = dyn_cast<Argument>(
|
||||
Address->stripInBoundsConstantOffsets())) {
|
||||
FI = FuncInfo.getArgumentFrameIndex(Arg);
|
||||
}
|
||||
|
||||
// llvm.dbg.addr is control dependent and always generates indirect
|
||||
// DBG_VALUE instructions. llvm.dbg.declare is handled as a frame index in
|
||||
// the MachineFunction variable table.
|
||||
if (FI != INT_MAX) {
|
||||
if (Intrinsic == Intrinsic::dbg_addr)
|
||||
DAG.AddDbgValue(DAG.getFrameIndexDbgValue(Variable, Expression, FI, dl,
|
||||
SDNodeOrder),
|
||||
getRoot().getNode(), isParameter);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SDValue &N = NodeMap[Address];
|
||||
if (!N.getNode() && isa<Argument>(Address))
|
||||
|
@ -5150,7 +5161,6 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) {
|
|||
if (const BitCastInst *BCI = dyn_cast<BitCastInst>(Address))
|
||||
Address = BCI->getOperand(0);
|
||||
// Parameters are handled specially.
|
||||
bool isParameter = Variable->isParameter() || isa<Argument>(Address);
|
||||
auto FINode = dyn_cast<FrameIndexSDNode>(N.getNode());
|
||||
if (isParameter && FINode) {
|
||||
// Byval parameter. We have a frame index at this point.
|
||||
|
|
|
@ -24,6 +24,11 @@
|
|||
using namespace llvm;
|
||||
using namespace llvm::dwarf;
|
||||
|
||||
cl::opt<bool>
|
||||
UseDbgAddr("use-dbg-addr",
|
||||
llvm::cl::desc("Use llvm.dbg.addr for all local variables"),
|
||||
cl::init(false));
|
||||
|
||||
DIBuilder::DIBuilder(Module &m, bool AllowUnresolvedNodes)
|
||||
: M(m), VMContext(M.getContext()), CUNode(nullptr),
|
||||
DeclareFn(nullptr), ValueFn(nullptr),
|
||||
|
@ -776,6 +781,11 @@ static Instruction *withDebugLoc(Instruction *I, const DILocation *DL) {
|
|||
return I;
|
||||
}
|
||||
|
||||
static Function *getDeclareIntrin(Module &M) {
|
||||
return Intrinsic::getDeclaration(&M, UseDbgAddr ? Intrinsic::dbg_addr
|
||||
: Intrinsic::dbg_declare);
|
||||
}
|
||||
|
||||
Instruction *DIBuilder::insertDeclare(Value *Storage, DILocalVariable *VarInfo,
|
||||
DIExpression *Expr, const DILocation *DL,
|
||||
Instruction *InsertBefore) {
|
||||
|
@ -785,7 +795,7 @@ Instruction *DIBuilder::insertDeclare(Value *Storage, DILocalVariable *VarInfo,
|
|||
VarInfo->getScope()->getSubprogram() &&
|
||||
"Expected matching subprograms");
|
||||
if (!DeclareFn)
|
||||
DeclareFn = Intrinsic::getDeclaration(&M, Intrinsic::dbg_declare);
|
||||
DeclareFn = getDeclareIntrin(M);
|
||||
|
||||
trackIfUnresolved(VarInfo);
|
||||
trackIfUnresolved(Expr);
|
||||
|
@ -804,7 +814,7 @@ Instruction *DIBuilder::insertDeclare(Value *Storage, DILocalVariable *VarInfo,
|
|||
VarInfo->getScope()->getSubprogram() &&
|
||||
"Expected matching subprograms");
|
||||
if (!DeclareFn)
|
||||
DeclareFn = Intrinsic::getDeclaration(&M, Intrinsic::dbg_declare);
|
||||
DeclareFn = getDeclareIntrin(M);
|
||||
|
||||
trackIfUnresolved(VarInfo);
|
||||
trackIfUnresolved(Expr);
|
||||
|
|
|
@ -4001,6 +4001,8 @@ void Verifier::visitIntrinsicCallSite(Intrinsic::ID ID, CallSite CS) {
|
|||
"invalid llvm.dbg.declare intrinsic call 1", CS);
|
||||
visitDbgIntrinsic("declare", cast<DbgInfoIntrinsic>(*CS.getInstruction()));
|
||||
break;
|
||||
case Intrinsic::dbg_addr: // llvm.dbg.addr
|
||||
visitDbgIntrinsic("addr", cast<DbgInfoIntrinsic>(*CS.getInstruction()));
|
||||
case Intrinsic::dbg_value: // llvm.dbg.value
|
||||
visitDbgIntrinsic("value", cast<DbgInfoIntrinsic>(*CS.getInstruction()));
|
||||
break;
|
||||
|
|
|
@ -2106,10 +2106,10 @@ Instruction *InstCombiner::visitAllocSite(Instruction &MI) {
|
|||
|
||||
// If we are removing an alloca with a dbg.declare, insert dbg.value calls
|
||||
// before each store.
|
||||
DbgDeclareInst *DDI = nullptr;
|
||||
TinyPtrVector<DbgInfoIntrinsic *> DIIs;
|
||||
std::unique_ptr<DIBuilder> DIB;
|
||||
if (isa<AllocaInst>(MI)) {
|
||||
DDI = FindAllocaDbgDeclare(&MI);
|
||||
DIIs = FindDbgAddrUses(&MI);
|
||||
DIB.reset(new DIBuilder(*MI.getModule(), /*AllowUnresolved=*/false));
|
||||
}
|
||||
|
||||
|
@ -2145,8 +2145,9 @@ Instruction *InstCombiner::visitAllocSite(Instruction &MI) {
|
|||
} else if (isa<BitCastInst>(I) || isa<GetElementPtrInst>(I) ||
|
||||
isa<AddrSpaceCastInst>(I)) {
|
||||
replaceInstUsesWith(*I, UndefValue::get(I->getType()));
|
||||
} else if (DDI && isa<StoreInst>(I)) {
|
||||
ConvertDebugDeclareToDebugValue(DDI, cast<StoreInst>(I), *DIB);
|
||||
} else if (auto *SI = dyn_cast<StoreInst>(I)) {
|
||||
for (auto *DII : DIIs)
|
||||
ConvertDebugDeclareToDebugValue(DII, SI, *DIB);
|
||||
}
|
||||
eraseInstFromFunction(*I);
|
||||
}
|
||||
|
@ -2159,8 +2160,8 @@ Instruction *InstCombiner::visitAllocSite(Instruction &MI) {
|
|||
None, "", II->getParent());
|
||||
}
|
||||
|
||||
if (DDI)
|
||||
eraseInstFromFunction(*DDI);
|
||||
for (auto *DII : DIIs)
|
||||
eraseInstFromFunction(*DII);
|
||||
|
||||
return eraseInstFromFunction(MI);
|
||||
}
|
||||
|
|
|
@ -4102,9 +4102,10 @@ bool SROA::splitAlloca(AllocaInst &AI, AllocaSlices &AS) {
|
|||
|
||||
// Migrate debug information from the old alloca to the new alloca(s)
|
||||
// and the individual partitions.
|
||||
if (DbgDeclareInst *DbgDecl = FindAllocaDbgDeclare(&AI)) {
|
||||
auto *Var = DbgDecl->getVariable();
|
||||
auto *Expr = DbgDecl->getExpression();
|
||||
TinyPtrVector<DbgInfoIntrinsic *> DbgDeclares = FindDbgAddrUses(&AI);
|
||||
if (!DbgDeclares.empty()) {
|
||||
auto *Var = DbgDeclares.front()->getVariable();
|
||||
auto *Expr = DbgDeclares.front()->getExpression();
|
||||
DIBuilder DIB(*AI.getModule(), /*AllowUnresolved*/ false);
|
||||
uint64_t AllocaSize = DL.getTypeSizeInBits(AI.getAllocatedType());
|
||||
for (auto Fragment : Fragments) {
|
||||
|
@ -4136,12 +4137,12 @@ bool SROA::splitAlloca(AllocaInst &AI, AllocaSlices &AS) {
|
|||
DIExpression::createFragmentExpression(Expr, Start, Size);
|
||||
}
|
||||
|
||||
// Remove any existing dbg.declare intrinsic describing the same alloca.
|
||||
if (DbgDeclareInst *OldDDI = FindAllocaDbgDeclare(Fragment.Alloca))
|
||||
OldDDI->eraseFromParent();
|
||||
// Remove any existing intrinsics describing the same alloca.
|
||||
for (DbgInfoIntrinsic *OldDII : FindDbgAddrUses(Fragment.Alloca))
|
||||
OldDII->eraseFromParent();
|
||||
|
||||
DIB.insertDeclare(Fragment.Alloca, Var, FragmentExpr,
|
||||
DbgDecl->getDebugLoc(), &AI);
|
||||
DbgDeclares.front()->getDebugLoc(), &AI);
|
||||
}
|
||||
}
|
||||
return Changed;
|
||||
|
@ -4246,6 +4247,15 @@ void SROA::deleteDeadInstructions(
|
|||
Instruction *I = DeadInsts.pop_back_val();
|
||||
DEBUG(dbgs() << "Deleting dead instruction: " << *I << "\n");
|
||||
|
||||
// If the instruction is an alloca, find the possible dbg.declare connected
|
||||
// to it, and remove it too. We must do this before calling RAUW or we will
|
||||
// not be able to find it.
|
||||
if (AllocaInst *AI = dyn_cast<AllocaInst>(I)) {
|
||||
DeletedAllocas.insert(AI);
|
||||
for (DbgInfoIntrinsic *OldDII : FindDbgAddrUses(AI))
|
||||
OldDII->eraseFromParent();
|
||||
}
|
||||
|
||||
I->replaceAllUsesWith(UndefValue::get(I->getType()));
|
||||
|
||||
for (Use &Operand : I->operands())
|
||||
|
@ -4256,12 +4266,6 @@ void SROA::deleteDeadInstructions(
|
|||
DeadInsts.insert(U);
|
||||
}
|
||||
|
||||
if (AllocaInst *AI = dyn_cast<AllocaInst>(I)) {
|
||||
DeletedAllocas.insert(AI);
|
||||
if (DbgDeclareInst *DbgDecl = FindAllocaDbgDeclare(AI))
|
||||
DbgDecl->eraseFromParent();
|
||||
}
|
||||
|
||||
++NumDeleted;
|
||||
I->eraseFromParent();
|
||||
}
|
||||
|
|
|
@ -1098,12 +1098,13 @@ static bool PhiHasDebugValue(DILocalVariable *DIVar,
|
|||
}
|
||||
|
||||
/// Inserts a llvm.dbg.value intrinsic before a store to an alloca'd value
|
||||
/// that has an associated llvm.dbg.decl intrinsic.
|
||||
void llvm::ConvertDebugDeclareToDebugValue(DbgDeclareInst *DDI,
|
||||
/// that has an associated llvm.dbg.declare or llvm.dbg.addr intrinsic.
|
||||
void llvm::ConvertDebugDeclareToDebugValue(DbgInfoIntrinsic *DII,
|
||||
StoreInst *SI, DIBuilder &Builder) {
|
||||
auto *DIVar = DDI->getVariable();
|
||||
assert(DII->isAddressOfVariable());
|
||||
auto *DIVar = DII->getVariable();
|
||||
assert(DIVar && "Missing variable");
|
||||
auto *DIExpr = DDI->getExpression();
|
||||
auto *DIExpr = DII->getExpression();
|
||||
Value *DV = SI->getOperand(0);
|
||||
|
||||
// If an argument is zero extended then use argument directly. The ZExt
|
||||
|
@ -1114,7 +1115,7 @@ void llvm::ConvertDebugDeclareToDebugValue(DbgDeclareInst *DDI,
|
|||
if (SExtInst *SExt = dyn_cast<SExtInst>(SI->getOperand(0)))
|
||||
ExtendedArg = dyn_cast<Argument>(SExt->getOperand(0));
|
||||
if (ExtendedArg) {
|
||||
// If this DDI was already describing only a fragment of a variable, ensure
|
||||
// If this DII was already describing only a fragment of a variable, ensure
|
||||
// that fragment is appropriately narrowed here.
|
||||
// But if a fragment wasn't used, describe the value as the original
|
||||
// argument (rather than the zext or sext) so that it remains described even
|
||||
|
@ -1127,23 +1128,23 @@ void llvm::ConvertDebugDeclareToDebugValue(DbgDeclareInst *DDI,
|
|||
DIExpr->elements_end() - 3);
|
||||
Ops.push_back(dwarf::DW_OP_LLVM_fragment);
|
||||
Ops.push_back(FragmentOffset);
|
||||
const DataLayout &DL = DDI->getModule()->getDataLayout();
|
||||
const DataLayout &DL = DII->getModule()->getDataLayout();
|
||||
Ops.push_back(DL.getTypeSizeInBits(ExtendedArg->getType()));
|
||||
DIExpr = Builder.createExpression(Ops);
|
||||
}
|
||||
DV = ExtendedArg;
|
||||
}
|
||||
if (!LdStHasDebugValue(DIVar, DIExpr, SI))
|
||||
Builder.insertDbgValueIntrinsic(DV, DIVar, DIExpr, DDI->getDebugLoc(),
|
||||
Builder.insertDbgValueIntrinsic(DV, DIVar, DIExpr, DII->getDebugLoc(),
|
||||
SI);
|
||||
}
|
||||
|
||||
/// Inserts a llvm.dbg.value intrinsic before a load of an alloca'd value
|
||||
/// that has an associated llvm.dbg.decl intrinsic.
|
||||
void llvm::ConvertDebugDeclareToDebugValue(DbgDeclareInst *DDI,
|
||||
/// that has an associated llvm.dbg.declare or llvm.dbg.addr intrinsic.
|
||||
void llvm::ConvertDebugDeclareToDebugValue(DbgInfoIntrinsic *DII,
|
||||
LoadInst *LI, DIBuilder &Builder) {
|
||||
auto *DIVar = DDI->getVariable();
|
||||
auto *DIExpr = DDI->getExpression();
|
||||
auto *DIVar = DII->getVariable();
|
||||
auto *DIExpr = DII->getExpression();
|
||||
assert(DIVar && "Missing variable");
|
||||
|
||||
if (LdStHasDebugValue(DIVar, DIExpr, LI))
|
||||
|
@ -1154,16 +1155,16 @@ void llvm::ConvertDebugDeclareToDebugValue(DbgDeclareInst *DDI,
|
|||
// preferable to keep tracking both the loaded value and the original
|
||||
// address in case the alloca can not be elided.
|
||||
Instruction *DbgValue = Builder.insertDbgValueIntrinsic(
|
||||
LI, DIVar, DIExpr, DDI->getDebugLoc(), (Instruction *)nullptr);
|
||||
LI, DIVar, DIExpr, DII->getDebugLoc(), (Instruction *)nullptr);
|
||||
DbgValue->insertAfter(LI);
|
||||
}
|
||||
|
||||
/// Inserts a llvm.dbg.value intrinsic after a phi
|
||||
/// that has an associated llvm.dbg.decl intrinsic.
|
||||
void llvm::ConvertDebugDeclareToDebugValue(DbgDeclareInst *DDI,
|
||||
/// Inserts a llvm.dbg.value intrinsic after a phi that has an associated
|
||||
/// llvm.dbg.declare or llvm.dbg.addr intrinsic.
|
||||
void llvm::ConvertDebugDeclareToDebugValue(DbgInfoIntrinsic *DII,
|
||||
PHINode *APN, DIBuilder &Builder) {
|
||||
auto *DIVar = DDI->getVariable();
|
||||
auto *DIExpr = DDI->getExpression();
|
||||
auto *DIVar = DII->getVariable();
|
||||
auto *DIExpr = DII->getExpression();
|
||||
assert(DIVar && "Missing variable");
|
||||
|
||||
if (PhiHasDebugValue(DIVar, DIExpr, APN))
|
||||
|
@ -1176,7 +1177,7 @@ void llvm::ConvertDebugDeclareToDebugValue(DbgDeclareInst *DDI,
|
|||
// insertion point.
|
||||
// FIXME: Insert dbg.value markers in the successors when appropriate.
|
||||
if (InsertionPt != BB->end())
|
||||
Builder.insertDbgValueIntrinsic(APN, DIVar, DIExpr, DDI->getDebugLoc(),
|
||||
Builder.insertDbgValueIntrinsic(APN, DIVar, DIExpr, DII->getDebugLoc(),
|
||||
&*InsertionPt);
|
||||
}
|
||||
|
||||
|
@ -1231,16 +1232,25 @@ bool llvm::LowerDbgDeclare(Function &F) {
|
|||
return true;
|
||||
}
|
||||
|
||||
/// FindAllocaDbgDeclare - Finds the llvm.dbg.declare intrinsic describing the
|
||||
/// alloca 'V', if any.
|
||||
DbgDeclareInst *llvm::FindAllocaDbgDeclare(Value *V) {
|
||||
if (auto *L = LocalAsMetadata::getIfExists(V))
|
||||
if (auto *MDV = MetadataAsValue::getIfExists(V->getContext(), L))
|
||||
for (User *U : MDV->users())
|
||||
if (DbgDeclareInst *DDI = dyn_cast<DbgDeclareInst>(U))
|
||||
return DDI;
|
||||
/// Finds all intrinsics declaring local variables as living in the memory that
|
||||
/// 'V' points to. This may include a mix of dbg.declare and
|
||||
/// dbg.addr intrinsics.
|
||||
TinyPtrVector<DbgInfoIntrinsic *> llvm::FindDbgAddrUses(Value *V) {
|
||||
auto *L = LocalAsMetadata::getIfExists(V);
|
||||
if (!L)
|
||||
return {};
|
||||
auto *MDV = MetadataAsValue::getIfExists(V->getContext(), L);
|
||||
if (!MDV)
|
||||
return {};
|
||||
|
||||
return nullptr;
|
||||
TinyPtrVector<DbgInfoIntrinsic *> Declares;
|
||||
for (User *U : MDV->users()) {
|
||||
if (auto *DII = dyn_cast<DbgInfoIntrinsic>(U))
|
||||
if (DII->isAddressOfVariable())
|
||||
Declares.push_back(DII);
|
||||
}
|
||||
|
||||
return Declares;
|
||||
}
|
||||
|
||||
void llvm::findDbgValues(SmallVectorImpl<DbgValueInst *> &DbgValues, Value *V) {
|
||||
|
@ -1251,23 +1261,24 @@ void llvm::findDbgValues(SmallVectorImpl<DbgValueInst *> &DbgValues, Value *V) {
|
|||
DbgValues.push_back(DVI);
|
||||
}
|
||||
|
||||
|
||||
bool llvm::replaceDbgDeclare(Value *Address, Value *NewAddress,
|
||||
Instruction *InsertBefore, DIBuilder &Builder,
|
||||
bool Deref, int Offset) {
|
||||
DbgDeclareInst *DDI = FindAllocaDbgDeclare(Address);
|
||||
if (!DDI)
|
||||
return false;
|
||||
DebugLoc Loc = DDI->getDebugLoc();
|
||||
auto *DIVar = DDI->getVariable();
|
||||
auto *DIExpr = DDI->getExpression();
|
||||
assert(DIVar && "Missing variable");
|
||||
DIExpr = DIExpression::prepend(DIExpr, Deref, Offset);
|
||||
// Insert llvm.dbg.declare immediately after the original alloca, and remove
|
||||
// old llvm.dbg.declare.
|
||||
Builder.insertDeclare(NewAddress, DIVar, DIExpr, Loc, InsertBefore);
|
||||
DDI->eraseFromParent();
|
||||
return true;
|
||||
auto DbgAddrs = FindDbgAddrUses(Address);
|
||||
for (DbgInfoIntrinsic *DII : DbgAddrs) {
|
||||
DebugLoc Loc = DII->getDebugLoc();
|
||||
auto *DIVar = DII->getVariable();
|
||||
auto *DIExpr = DII->getExpression();
|
||||
assert(DIVar && "Missing variable");
|
||||
DIExpr = DIExpression::prepend(DIExpr, Deref, Offset);
|
||||
// Insert llvm.dbg.declare immediately after InsertBefore, and remove old
|
||||
// llvm.dbg.declare.
|
||||
Builder.insertDeclare(NewAddress, DIVar, DIExpr, Loc, InsertBefore);
|
||||
if (DII == InsertBefore)
|
||||
InsertBefore = &*std::next(InsertBefore->getIterator());
|
||||
DII->eraseFromParent();
|
||||
}
|
||||
return !DbgAddrs.empty();
|
||||
}
|
||||
|
||||
bool llvm::replaceDbgDeclareForAlloca(AllocaInst *AI, Value *NewAllocaAddress,
|
||||
|
|
|
@ -103,7 +103,7 @@ struct AllocaInfo {
|
|||
bool OnlyUsedInOneBlock;
|
||||
|
||||
Value *AllocaPointerVal;
|
||||
DbgDeclareInst *DbgDeclare;
|
||||
TinyPtrVector<DbgInfoIntrinsic*> DbgDeclares;
|
||||
|
||||
void clear() {
|
||||
DefiningBlocks.clear();
|
||||
|
@ -112,7 +112,7 @@ struct AllocaInfo {
|
|||
OnlyBlock = nullptr;
|
||||
OnlyUsedInOneBlock = true;
|
||||
AllocaPointerVal = nullptr;
|
||||
DbgDeclare = nullptr;
|
||||
DbgDeclares.clear();
|
||||
}
|
||||
|
||||
/// Scan the uses of the specified alloca, filling in the AllocaInfo used
|
||||
|
@ -147,7 +147,7 @@ struct AllocaInfo {
|
|||
}
|
||||
}
|
||||
|
||||
DbgDeclare = FindAllocaDbgDeclare(AI);
|
||||
DbgDeclares = FindDbgAddrUses(AI);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -245,7 +245,7 @@ struct PromoteMem2Reg {
|
|||
/// For each alloca, we keep track of the dbg.declare intrinsic that
|
||||
/// describes it, if any, so that we can convert it to a dbg.value
|
||||
/// intrinsic if the alloca gets promoted.
|
||||
SmallVector<DbgDeclareInst *, 8> AllocaDbgDeclares;
|
||||
SmallVector<TinyPtrVector<DbgInfoIntrinsic *>, 8> AllocaDbgDeclares;
|
||||
|
||||
/// The set of basic blocks the renamer has already visited.
|
||||
///
|
||||
|
@ -409,11 +409,11 @@ static bool rewriteSingleStoreAlloca(AllocaInst *AI, AllocaInfo &Info,
|
|||
|
||||
// Record debuginfo for the store and remove the declaration's
|
||||
// debuginfo.
|
||||
if (DbgDeclareInst *DDI = Info.DbgDeclare) {
|
||||
for (DbgInfoIntrinsic *DII : Info.DbgDeclares) {
|
||||
DIBuilder DIB(*AI->getModule(), /*AllowUnresolved*/ false);
|
||||
ConvertDebugDeclareToDebugValue(DDI, Info.OnlyStore, DIB);
|
||||
DDI->eraseFromParent();
|
||||
LBI.deleteValue(DDI);
|
||||
ConvertDebugDeclareToDebugValue(DII, Info.OnlyStore, DIB);
|
||||
DII->eraseFromParent();
|
||||
LBI.deleteValue(DII);
|
||||
}
|
||||
// Remove the (now dead) store and alloca.
|
||||
Info.OnlyStore->eraseFromParent();
|
||||
|
@ -505,9 +505,9 @@ static bool promoteSingleBlockAlloca(AllocaInst *AI, const AllocaInfo &Info,
|
|||
while (!AI->use_empty()) {
|
||||
StoreInst *SI = cast<StoreInst>(AI->user_back());
|
||||
// Record debuginfo for the store before removing it.
|
||||
if (DbgDeclareInst *DDI = Info.DbgDeclare) {
|
||||
for (DbgInfoIntrinsic *DII : Info.DbgDeclares) {
|
||||
DIBuilder DIB(*AI->getModule(), /*AllowUnresolved*/ false);
|
||||
ConvertDebugDeclareToDebugValue(DDI, SI, DIB);
|
||||
ConvertDebugDeclareToDebugValue(DII, SI, DIB);
|
||||
}
|
||||
SI->eraseFromParent();
|
||||
LBI.deleteValue(SI);
|
||||
|
@ -517,9 +517,9 @@ static bool promoteSingleBlockAlloca(AllocaInst *AI, const AllocaInfo &Info,
|
|||
LBI.deleteValue(AI);
|
||||
|
||||
// The alloca's debuginfo can be removed as well.
|
||||
if (DbgDeclareInst *DDI = Info.DbgDeclare) {
|
||||
DDI->eraseFromParent();
|
||||
LBI.deleteValue(DDI);
|
||||
for (DbgInfoIntrinsic *DII : Info.DbgDeclares) {
|
||||
DII->eraseFromParent();
|
||||
LBI.deleteValue(DII);
|
||||
}
|
||||
|
||||
++NumLocalPromoted;
|
||||
|
@ -587,8 +587,8 @@ void PromoteMem2Reg::run() {
|
|||
}
|
||||
|
||||
// Remember the dbg.declare intrinsic describing this alloca, if any.
|
||||
if (Info.DbgDeclare)
|
||||
AllocaDbgDeclares[AllocaNum] = Info.DbgDeclare;
|
||||
if (!Info.DbgDeclares.empty())
|
||||
AllocaDbgDeclares[AllocaNum] = Info.DbgDeclares;
|
||||
|
||||
// Keep the reverse mapping of the 'Allocas' array for the rename pass.
|
||||
AllocaLookup[Allocas[AllocaNum]] = AllocaNum;
|
||||
|
@ -666,9 +666,9 @@ void PromoteMem2Reg::run() {
|
|||
}
|
||||
|
||||
// Remove alloca's dbg.declare instrinsics from the function.
|
||||
for (DbgDeclareInst *DDI : AllocaDbgDeclares)
|
||||
if (DDI)
|
||||
DDI->eraseFromParent();
|
||||
for (auto &Declares : AllocaDbgDeclares)
|
||||
for (auto *DII : Declares)
|
||||
DII->eraseFromParent();
|
||||
|
||||
// Loop over all of the PHI nodes and see if there are any that we can get
|
||||
// rid of because they merge all of the same incoming values. This can
|
||||
|
@ -895,8 +895,8 @@ NextIteration:
|
|||
|
||||
// The currently active variable for this block is now the PHI.
|
||||
IncomingVals[AllocaNo] = APN;
|
||||
if (DbgDeclareInst *DDI = AllocaDbgDeclares[AllocaNo])
|
||||
ConvertDebugDeclareToDebugValue(DDI, APN, DIB);
|
||||
for (DbgInfoIntrinsic *DII : AllocaDbgDeclares[AllocaNo])
|
||||
ConvertDebugDeclareToDebugValue(DII, APN, DIB);
|
||||
|
||||
// Get the next phi node.
|
||||
++PNI;
|
||||
|
@ -952,8 +952,8 @@ NextIteration:
|
|||
// what value were we writing?
|
||||
IncomingVals[ai->second] = SI->getOperand(0);
|
||||
// Record debuginfo for the store before removing it.
|
||||
if (DbgDeclareInst *DDI = AllocaDbgDeclares[ai->second])
|
||||
ConvertDebugDeclareToDebugValue(DDI, SI, DIB);
|
||||
for (DbgInfoIntrinsic *DII : AllocaDbgDeclares[ai->second])
|
||||
ConvertDebugDeclareToDebugValue(DII, SI, DIB);
|
||||
BB->getInstList().erase(SI);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
; RUN: llc %s -o %t.s
|
||||
; RUN: llvm-mc %t.s -filetype=obj -triple=x86_64-windows-msvc -o %t.o
|
||||
; RUN: FileCheck %s < %t.s --check-prefix=ASM
|
||||
; RUN: llvm-dwarfdump %t.o | FileCheck %s --check-prefix=DWARF
|
||||
|
||||
; In this example, the variable lives mostly in memory, but at the point of the
|
||||
; assignment to global, it lives nowhere, and is described as the constant
|
||||
; value 1.
|
||||
|
||||
; C source:
|
||||
;
|
||||
; void escape(int *);
|
||||
; extern int global;
|
||||
; void f(int x) {
|
||||
; escape(&x);
|
||||
; x = 1; // DSE should delete and insert dbg.value(i32 1)
|
||||
; global = x;
|
||||
; x = 2; // DSE should insert dbg.addr
|
||||
; escape(&x);
|
||||
; }
|
||||
|
||||
; ModuleID = 'dse.c'
|
||||
source_filename = "dse.c"
|
||||
target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
|
||||
target triple = "x86_64-pc-windows-msvc19.0.24215"
|
||||
|
||||
declare void @llvm.dbg.addr(metadata, metadata, metadata) #2
|
||||
declare void @llvm.dbg.value(metadata, metadata, metadata) #2
|
||||
declare void @escape(i32*)
|
||||
|
||||
@global = external global i32, align 4
|
||||
|
||||
; Function Attrs: nounwind uwtable
|
||||
define void @f(i32 %x) #0 !dbg !8 {
|
||||
entry:
|
||||
%x.addr = alloca i32, align 4
|
||||
store i32 %x, i32* %x.addr, align 4
|
||||
call void @llvm.dbg.addr(metadata i32* %x.addr, metadata !13, metadata !DIExpression()), !dbg !18
|
||||
call void @escape(i32* %x.addr), !dbg !19
|
||||
call void @llvm.dbg.value(metadata i32 1, metadata !13, metadata !DIExpression()), !dbg !20
|
||||
store i32 1, i32* @global, align 4, !dbg !22
|
||||
call void @llvm.dbg.addr(metadata i32* %x.addr, metadata !13, metadata !DIExpression()), !dbg !23
|
||||
store i32 2, i32* %x.addr, align 4, !dbg !23
|
||||
call void @escape(i32* %x.addr), !dbg !24
|
||||
ret void, !dbg !25
|
||||
}
|
||||
|
||||
; ASM-LABEL: f: # @f
|
||||
; ASM: movl %ecx, [[OFF_X:[0-9]+]](%rsp)
|
||||
; ASM: #DEBUG_VALUE: f:x <- [DW_OP_plus_uconst [[OFF_X]]] [%RSP+0]
|
||||
; ASM: callq escape
|
||||
; ASM: #DEBUG_VALUE: f:x <- 1
|
||||
; ASM: movl $1, global(%rip)
|
||||
; FIXME: Needs a fix to LiveDebugVariables
|
||||
; ASMX: #DEBUG_VALUE: f:x <- [DW_OP_plus_uconst [[OFF_X]]] [%RSP+0]
|
||||
; ASM: movl $2, [[OFF_X]](%rsp)
|
||||
; ASM: callq escape
|
||||
; ASM: retq
|
||||
|
||||
; DWARF: DW_TAG_formal_parameter
|
||||
; DWARF-NEXT: DW_AT_location (0x00000000
|
||||
; DWARF-NEXT: {{[^:]*}}: DW_OP_breg7 RSP+{{[0-9]+}}
|
||||
; DWARF-NEXT: {{[^:]*}}: DW_OP_consts +1, DW_OP_stack_value
|
||||
; FIXME: Needs a fix to LiveDebugVariables
|
||||
; DWARFX-NEXT: {{[^:]*}}: DW_OP_breg7 RSP+{{[0-9]+}})
|
||||
; DWARF-NEXT: DW_AT_name ("x")
|
||||
|
||||
attributes #0 = { nounwind uwtable }
|
||||
attributes #2 = { nounwind readnone speculatable }
|
||||
|
||||
!llvm.dbg.cu = !{!0}
|
||||
!llvm.module.flags = !{!3, !4, !5, !6}
|
||||
!llvm.ident = !{!7}
|
||||
|
||||
!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 6.0.0 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
|
||||
!1 = !DIFile(filename: "dse.c", directory: "C:\5Csrc\5Cllvm-project\5Cbuild")
|
||||
!2 = !{}
|
||||
!3 = !{i32 2, !"Dwarf Version", i32 4}
|
||||
!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 6.0.0 "}
|
||||
!8 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 3, type: !9, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: true, unit: !0, variables: !12)
|
||||
!9 = !DISubroutineType(types: !10)
|
||||
!10 = !{null, !11}
|
||||
!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
|
||||
!12 = !{!13}
|
||||
!13 = !DILocalVariable(name: "x", arg: 1, scope: !8, file: !1, line: 3, type: !11)
|
||||
!14 = !{!15, !15, i64 0}
|
||||
!15 = !{!"int", !16, i64 0}
|
||||
!16 = !{!"omnipotent char", !17, i64 0}
|
||||
!17 = !{!"Simple C/C++ TBAA"}
|
||||
!18 = !DILocation(line: 3, column: 12, scope: !8)
|
||||
!19 = !DILocation(line: 4, column: 3, scope: !8)
|
||||
!20 = !DILocation(line: 5, column: 5, scope: !8)
|
||||
!21 = !DILocation(line: 6, column: 12, scope: !8)
|
||||
!22 = !DILocation(line: 6, column: 10, scope: !8)
|
||||
!23 = !DILocation(line: 7, column: 5, scope: !8)
|
||||
!24 = !DILocation(line: 8, column: 3, scope: !8)
|
||||
!25 = !DILocation(line: 9, column: 1, scope: !8)
|
|
@ -0,0 +1,67 @@
|
|||
; RUN: llc %s -o %t.s
|
||||
; RUN: llvm-mc -triple x86_64--linux %t.s -filetype=obj -o %t.o
|
||||
; RUN: FileCheck < %t.s %s
|
||||
; RUN: llvm-dwarfdump %t.o | FileCheck %s --check-prefix=DWARF
|
||||
|
||||
; Unlike dbg.declare, dbg.addr should be lowered to DBG_VALUE instructions. It
|
||||
; is control-dependent.
|
||||
|
||||
; CHECK-LABEL: use_dbg_addr:
|
||||
; CHECK: #DEBUG_VALUE: use_dbg_addr:o <- [%RSP+0]
|
||||
|
||||
; FIXME: Avoid the use of a single-location location list and use
|
||||
; DW_AT_start_offset instead.
|
||||
|
||||
; DWARF: DW_TAG_variable
|
||||
; DWARF-NEXT: DW_AT_location (0x00000000
|
||||
; DWARF-NEXT: 0x{{.*}} - 0x{{.*}}: DW_OP_breg7 RSP+0)
|
||||
; DWARF-NEXT: DW_AT_name ("o")
|
||||
|
||||
|
||||
; ModuleID = 't.c'
|
||||
source_filename = "t.c"
|
||||
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
||||
target triple = "x86_64--linux"
|
||||
|
||||
%struct.Foo = type { i32 }
|
||||
|
||||
; Function Attrs: noinline nounwind uwtable
|
||||
define void @use_dbg_addr() #0 !dbg !7 {
|
||||
entry:
|
||||
%o = alloca %struct.Foo, align 4
|
||||
call void @llvm.dbg.addr(metadata %struct.Foo* %o, metadata !10, metadata !15), !dbg !16
|
||||
call void @escape_foo(%struct.Foo* %o), !dbg !17
|
||||
ret void, !dbg !18
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind readnone speculatable
|
||||
declare void @llvm.dbg.addr(metadata, metadata, metadata) #1
|
||||
|
||||
declare void @escape_foo(%struct.Foo*)
|
||||
|
||||
attributes #0 = { noinline nounwind uwtable }
|
||||
attributes #1 = { nounwind readnone speculatable }
|
||||
|
||||
!llvm.dbg.cu = !{!0}
|
||||
!llvm.module.flags = !{!3, !4, !5}
|
||||
!llvm.ident = !{!6}
|
||||
|
||||
!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: "t.c", directory: "C:\5Csrc\5Cllvm-project\5Cbuild")
|
||||
!2 = !{}
|
||||
!3 = !{i32 2, !"Dwarf Version", i32 4}
|
||||
!4 = !{i32 2, !"Debug Info Version", i32 3}
|
||||
!5 = !{i32 1, !"wchar_size", i32 4}
|
||||
!6 = !{!"clang version 6.0.0 "}
|
||||
!7 = distinct !DISubprogram(name: "use_dbg_addr", scope: !1, file: !1, line: 3, type: !8, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2)
|
||||
!8 = !DISubroutineType(types: !9)
|
||||
!9 = !{null}
|
||||
!10 = !DILocalVariable(name: "o", scope: !7, file: !1, line: 4, type: !11)
|
||||
!11 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "Foo", file: !1, line: 1, size: 32, elements: !12)
|
||||
!12 = !{!13}
|
||||
!13 = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: !11, file: !1, line: 1, baseType: !14, size: 32)
|
||||
!14 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
|
||||
!15 = !DIExpression()
|
||||
!16 = !DILocation(line: 4, column: 14, scope: !7)
|
||||
!17 = !DILocation(line: 5, column: 3, scope: !7)
|
||||
!18 = !DILocation(line: 6, column: 1, scope: !7)
|
|
@ -20,10 +20,10 @@ target triple = "x86_64-unknown-linux-gnu"
|
|||
;
|
||||
; There should be no debug info for the padding.
|
||||
; CHECK-NOT: DW_OP_LLVM_fragment, 56
|
||||
; CHECK: DIExpression(DW_OP_LLVM_fragment, 32, 24)
|
||||
; CHECK-NOT: DW_OP_LLVM_fragment, 56
|
||||
; CHECK: DIExpression(DW_OP_LLVM_fragment, 0, 32)
|
||||
; CHECK-NOT: DW_OP_LLVM_fragment, 56
|
||||
; CHECK: DIExpression(DW_OP_LLVM_fragment, 32, 24)
|
||||
; CHECK-NOT: DW_OP_LLVM_fragment, 56
|
||||
%struct.prog_src_register = type { i32, i24 }
|
||||
|
||||
; Function Attrs: nounwind
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
; RUN: opt -S -sroa -o - %s | FileCheck %s
|
||||
|
||||
; SROA should split the alloca in two new ones, each with its own dbg.declare.
|
||||
; The original alloca and dbg.declare should be removed.
|
||||
|
||||
define void @f1() {
|
||||
entry:
|
||||
%0 = alloca [9 x i32]
|
||||
call void @llvm.dbg.declare(metadata [9 x i32]* %0, metadata !11, metadata !DIExpression()), !dbg !17
|
||||
%1 = bitcast [9 x i32]* %0 to i8*
|
||||
call void @llvm.memset.p0i8.i64(i8* %1, i8 0, i64 36, i32 16, i1 true)
|
||||
%2 = getelementptr [9 x i32], [9 x i32]* %0, i32 0, i32 0
|
||||
store volatile i32 1, i32* %2
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind readnone speculatable
|
||||
declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
|
||||
|
||||
; Function Attrs: argmemonly nounwind
|
||||
declare void @llvm.memset.p0i8.i64(i8* nocapture writeonly, i8, i64, i32, i1) #0
|
||||
|
||||
attributes #0 = { argmemonly nounwind }
|
||||
attributes #1 = { nounwind readnone speculatable }
|
||||
|
||||
!llvm.dbg.cu = !{!0}
|
||||
!llvm.module.flags = !{!3, !4, !5}
|
||||
!llvm.ident = !{!6}
|
||||
|
||||
!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 6.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
|
||||
!1 = !DIFile(filename: "foo.c", directory: "/bar")
|
||||
!2 = !{}
|
||||
!3 = !{i32 2, !"Dwarf Version", i32 4}
|
||||
!4 = !{i32 2, !"Debug Info Version", i32 3}
|
||||
!5 = !{i32 1, !"wchar_size", i32 4}
|
||||
!6 = !{!"clang version 6.0.0"}
|
||||
!7 = distinct !DISubprogram(name: "f1", scope: !1, file: !1, line: 1, type: !8, isLocal: false, isDefinition: true, scopeLine: 2, flags: DIFlagPrototyped, isOptimized: true, unit: !0, variables: !10)
|
||||
!8 = !DISubroutineType(types: !9)
|
||||
!9 = !{null}
|
||||
!10 = !{!11}
|
||||
!11 = !DILocalVariable(name: "b", scope: !7, file: !1, line: 3, type: !12)
|
||||
!12 = !DICompositeType(tag: DW_TAG_array_type, baseType: !13, size: 288, elements: !15)
|
||||
!13 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !14)
|
||||
!14 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
|
||||
!15 = !{!16}
|
||||
!16 = !DISubrange(count: 9)
|
||||
!17 = !DILocation(line: 3, column: 18, scope: !7)
|
||||
|
||||
; CHECK-NOT: = alloca [9 x i32]
|
||||
; CHECK-NOT: call void @llvm.dbg.declare(metadata [9 x i32]*
|
||||
|
||||
; CHECK: %[[VAR1:.*]] = alloca i32
|
||||
; CHECK-NEXT: %[[VAR2:.*]] = alloca [8 x i32]
|
||||
; CHECK-NEXT: call void @llvm.dbg.declare(metadata i32* %[[VAR1]]
|
||||
; CHECK-NEXT: call void @llvm.dbg.declare(metadata [8 x i32]* %[[VAR2]]
|
||||
|
||||
; CHECK-NOT: = alloca [9 x i32]
|
||||
; CHECK-NOT: call void @llvm.dbg.declare(metadata [9 x i32]*
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
; RUN: opt -mem2reg -S < %s | FileCheck %s -implicit-check-not="call void @llvm.dbg.addr"
|
||||
|
||||
; This example is intended to simulate this pass pipeline, which may not exist
|
||||
; in practice:
|
||||
; 1. DSE f from the original C source
|
||||
; 2. Inline escape
|
||||
; 3. mem2reg
|
||||
; This exercises the corner case of multiple llvm.dbg.addr intrinsics.
|
||||
|
||||
; C source:
|
||||
;
|
||||
; void escape(int *px) { ++*px; }
|
||||
; extern int global;
|
||||
; void f(int x) {
|
||||
; escape(&x);
|
||||
; x = 1; // DSE should delete and insert dbg.value(i32 1)
|
||||
; global = x;
|
||||
; x = 2; // DSE should insert dbg.addr
|
||||
; escape(&x);
|
||||
; }
|
||||
|
||||
; ModuleID = 'dse.c'
|
||||
source_filename = "dse.c"
|
||||
target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
|
||||
target triple = "x86_64-pc-windows-msvc19.0.24215"
|
||||
|
||||
declare void @llvm.dbg.addr(metadata, metadata, metadata) #2
|
||||
declare void @llvm.dbg.value(metadata, metadata, metadata) #2
|
||||
|
||||
@global = external global i32, align 4
|
||||
|
||||
; Function Attrs: nounwind uwtable
|
||||
define void @f(i32 %x) #0 !dbg !8 {
|
||||
entry:
|
||||
%x.addr = alloca i32, align 4
|
||||
store i32 %x, i32* %x.addr, align 4
|
||||
call void @llvm.dbg.addr(metadata i32* %x.addr, metadata !13, metadata !DIExpression()), !dbg !18
|
||||
%ld.1 = load i32, i32* %x.addr, align 4, !dbg !19
|
||||
%inc.1 = add nsw i32 %ld.1, 1, !dbg !19
|
||||
store i32 %inc.1, i32* %x.addr, align 4, !dbg !19
|
||||
call void @llvm.dbg.value(metadata i32 1, metadata !13, metadata !DIExpression()), !dbg !20
|
||||
store i32 1, i32* @global, align 4, !dbg !22
|
||||
call void @llvm.dbg.addr(metadata i32* %x.addr, metadata !13, metadata !DIExpression()), !dbg !23
|
||||
store i32 2, i32* %x.addr, align 4, !dbg !23
|
||||
%ld.2 = load i32, i32* %x.addr, align 4, !dbg !19
|
||||
%inc.2 = add nsw i32 %ld.2, 1, !dbg !19
|
||||
store i32 %inc.2, i32* %x.addr, align 4, !dbg !19
|
||||
ret void, !dbg !25
|
||||
}
|
||||
|
||||
; CHECK-LABEL: define void @f(i32 %x)
|
||||
; CHECK: call void @llvm.dbg.value(metadata i32 %x, metadata !13, metadata !DIExpression())
|
||||
; CHECK: %inc.1 = add nsw i32 %x, 1
|
||||
; CHECK: call void @llvm.dbg.value(metadata i32 %inc.1, metadata !13, metadata !DIExpression())
|
||||
; CHECK: call void @llvm.dbg.value(metadata i32 1, metadata !13, metadata !DIExpression())
|
||||
; CHECK: store i32 1, i32* @global, align 4
|
||||
; CHECK: call void @llvm.dbg.value(metadata i32 2, metadata !13, metadata !DIExpression())
|
||||
; CHECK: %inc.2 = add nsw i32 2, 1
|
||||
; CHECK: call void @llvm.dbg.value(metadata i32 %inc.2, metadata !13, metadata !DIExpression())
|
||||
; CHECK: ret void
|
||||
|
||||
attributes #0 = { nounwind uwtable }
|
||||
attributes #2 = { nounwind readnone speculatable }
|
||||
|
||||
!llvm.dbg.cu = !{!0}
|
||||
!llvm.module.flags = !{!3, !4, !5, !6}
|
||||
!llvm.ident = !{!7}
|
||||
|
||||
!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 6.0.0 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
|
||||
!1 = !DIFile(filename: "dse.c", directory: "C:\5Csrc\5Cllvm-project\5Cbuild")
|
||||
!2 = !{}
|
||||
!3 = !{i32 2, !"Dwarf Version", i32 4}
|
||||
!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 6.0.0 "}
|
||||
!8 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 3, type: !9, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: true, unit: !0, variables: !12)
|
||||
!9 = !DISubroutineType(types: !10)
|
||||
!10 = !{null, !11}
|
||||
!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
|
||||
!12 = !{!13}
|
||||
!13 = !DILocalVariable(name: "x", arg: 1, scope: !8, file: !1, line: 3, type: !11)
|
||||
!14 = !{!15, !15, i64 0}
|
||||
!15 = !{!"int", !16, i64 0}
|
||||
!16 = !{!"omnipotent char", !17, i64 0}
|
||||
!17 = !{!"Simple C/C++ TBAA"}
|
||||
!18 = !DILocation(line: 3, column: 12, scope: !8)
|
||||
!19 = !DILocation(line: 4, column: 3, scope: !8)
|
||||
!20 = !DILocation(line: 5, column: 5, scope: !8)
|
||||
!21 = !DILocation(line: 6, column: 12, scope: !8)
|
||||
!22 = !DILocation(line: 6, column: 10, scope: !8)
|
||||
!23 = !DILocation(line: 7, column: 5, scope: !8)
|
||||
!24 = !DILocation(line: 8, column: 3, scope: !8)
|
||||
!25 = !DILocation(line: 9, column: 1, scope: !8)
|
|
@ -0,0 +1,91 @@
|
|||
; RUN: opt -mem2reg -S < %s | FileCheck %s
|
||||
|
||||
; ModuleID = 'newvars.c'
|
||||
source_filename = "newvars.c"
|
||||
target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
|
||||
target triple = "x86_64-pc-windows-msvc19.0.24215"
|
||||
|
||||
; Function Attrs: nounwind uwtable
|
||||
define i32 @if_else(i32 %cond, i32 %a, i32 %b) !dbg !8 {
|
||||
entry:
|
||||
%x = alloca i32, align 4
|
||||
call void @llvm.dbg.addr(metadata i32* %x, metadata !16, metadata !DIExpression()), !dbg !26
|
||||
store i32 %a, i32* %x, align 4, !dbg !26, !tbaa !17
|
||||
%tobool = icmp ne i32 %cond, 0, !dbg !28
|
||||
br i1 %tobool, label %if.then, label %if.else, !dbg !30
|
||||
|
||||
if.then: ; preds = %entry
|
||||
store i32 0, i32* %x, align 4, !dbg !31, !tbaa !17
|
||||
br label %if.end, !dbg !33
|
||||
|
||||
if.else: ; preds = %entry
|
||||
store i32 %b, i32* %x, align 4, !dbg !36, !tbaa !17
|
||||
br label %if.end
|
||||
|
||||
if.end: ; preds = %if.else, %if.then
|
||||
%rv = load i32, i32* %x, align 4, !dbg !37, !tbaa !17
|
||||
ret i32 %rv, !dbg !39
|
||||
}
|
||||
|
||||
; CHECK-LABEL: define i32 @if_else({{.*}})
|
||||
; CHECK: entry:
|
||||
; CHECK-NOT: alloca i32
|
||||
; CHECK: call void @llvm.dbg.value(metadata i32 %a, metadata ![[X_LOCAL:[0-9]+]], metadata !DIExpression())
|
||||
; CHECK: if.then: ; preds = %entry
|
||||
; CHECK: call void @llvm.dbg.value(metadata i32 0, metadata ![[X_LOCAL]], metadata !DIExpression())
|
||||
; CHECK: if.else: ; preds = %entry
|
||||
; CHECK: call void @llvm.dbg.value(metadata i32 %b, metadata ![[X_LOCAL]], metadata !DIExpression())
|
||||
; CHECK: if.end: ; preds = %if.else, %if.then
|
||||
; CHECK: %[[PHI:[^ ]*]] = phi i32 [ 0, %if.then ], [ %b, %if.else ]
|
||||
; CHECK: call void @llvm.dbg.value(metadata i32 %[[PHI]], metadata ![[X_LOCAL]], metadata !DIExpression())
|
||||
; CHECK: ret i32
|
||||
|
||||
; CHECK: ![[X_LOCAL]] = !DILocalVariable(name: "x", {{.*}})
|
||||
|
||||
; Function Attrs: nounwind readnone speculatable
|
||||
declare void @llvm.dbg.declare(metadata, metadata, metadata)
|
||||
declare void @llvm.dbg.addr(metadata, metadata, metadata)
|
||||
|
||||
!llvm.dbg.cu = !{!0}
|
||||
!llvm.module.flags = !{!3, !4, !5, !6}
|
||||
!llvm.ident = !{!7}
|
||||
|
||||
!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 6.0.0 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
|
||||
!1 = !DIFile(filename: "newvars.c", directory: "C:\5Csrc\5Cllvm-project\5Cbuild")
|
||||
!2 = !{}
|
||||
!3 = !{i32 2, !"Dwarf Version", i32 4}
|
||||
!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 6.0.0 "}
|
||||
!8 = distinct !DISubprogram(name: "if_else", scope: !1, file: !1, line: 1, type: !9, isLocal: false, isDefinition: true, scopeLine: 1, flags: DIFlagPrototyped, isOptimized: true, unit: !0, variables: !12)
|
||||
!9 = !DISubroutineType(types: !10)
|
||||
!10 = !{!11, !11, !11, !11}
|
||||
!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
|
||||
!12 = !{!13, !14, !15, !16}
|
||||
!13 = !DILocalVariable(name: "b", arg: 3, scope: !8, file: !1, line: 1, type: !11)
|
||||
!14 = !DILocalVariable(name: "a", arg: 2, scope: !8, file: !1, line: 1, type: !11)
|
||||
!15 = !DILocalVariable(name: "cond", arg: 1, scope: !8, file: !1, line: 1, type: !11)
|
||||
!16 = !DILocalVariable(name: "x", scope: !8, file: !1, line: 2, type: !11)
|
||||
!17 = !{!18, !18, i64 0}
|
||||
!18 = !{!"int", !19, i64 0}
|
||||
!19 = !{!"omnipotent char", !20, i64 0}
|
||||
!20 = !{!"Simple C/C++ TBAA"}
|
||||
!22 = !DILocation(line: 1, column: 34, scope: !8)
|
||||
!23 = !DILocation(line: 1, column: 27, scope: !8)
|
||||
!24 = !DILocation(line: 1, column: 17, scope: !8)
|
||||
!25 = !DILocation(line: 2, column: 3, scope: !8)
|
||||
!26 = !DILocation(line: 2, column: 7, scope: !8)
|
||||
!27 = !DILocation(line: 2, column: 11, scope: !8)
|
||||
!28 = !DILocation(line: 3, column: 7, scope: !29)
|
||||
!29 = distinct !DILexicalBlock(scope: !8, file: !1, line: 3, column: 7)
|
||||
!30 = !DILocation(line: 3, column: 7, scope: !8)
|
||||
!31 = !DILocation(line: 4, column: 7, scope: !32)
|
||||
!32 = distinct !DILexicalBlock(scope: !29, file: !1, line: 3, column: 13)
|
||||
!33 = !DILocation(line: 5, column: 3, scope: !32)
|
||||
!34 = !DILocation(line: 6, column: 9, scope: !35)
|
||||
!35 = distinct !DILexicalBlock(scope: !29, file: !1, line: 5, column: 10)
|
||||
!36 = !DILocation(line: 6, column: 7, scope: !35)
|
||||
!37 = !DILocation(line: 8, column: 10, scope: !8)
|
||||
!38 = !DILocation(line: 9, column: 1, scope: !8)
|
||||
!39 = !DILocation(line: 8, column: 3, scope: !8)
|
|
@ -0,0 +1,127 @@
|
|||
; RUN: opt -use-dbg-addr -sroa -S < %s | FileCheck %s
|
||||
|
||||
; ModuleID = '<stdin>'
|
||||
source_filename = "newvars.c"
|
||||
target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
|
||||
target triple = "x86_64-pc-windows-msvc19.0.24215"
|
||||
|
||||
%struct.Pair = type { i32, i32 }
|
||||
|
||||
@pair = internal global %struct.Pair zeroinitializer
|
||||
|
||||
; Function Attrs: nounwind uwtable
|
||||
define void @if_else(i32 %cond, i32 %a, i32 %b) !dbg !8 {
|
||||
entry:
|
||||
%p = alloca %struct.Pair, align 4
|
||||
%0 = bitcast %struct.Pair* %p to i8*, !dbg !25
|
||||
call void @llvm.dbg.addr(metadata %struct.Pair* %p, metadata !20, metadata !DIExpression()), !dbg !26
|
||||
%x = getelementptr inbounds %struct.Pair, %struct.Pair* %p, i32 0, i32 0, !dbg !27
|
||||
store i32 %a, i32* %x, align 4, !dbg !28
|
||||
%y = getelementptr inbounds %struct.Pair, %struct.Pair* %p, i32 0, i32 1, !dbg !34
|
||||
store i32 %b, i32* %y, align 4, !dbg !35
|
||||
%tobool = icmp ne i32 %cond, 0, !dbg !37
|
||||
br i1 %tobool, label %if.then, label %if.else, !dbg !39
|
||||
|
||||
if.then: ; preds = %entry
|
||||
%x1 = getelementptr inbounds %struct.Pair, %struct.Pair* %p, i32 0, i32 0, !dbg !40
|
||||
store i32 0, i32* %x1, align 4, !dbg !42
|
||||
%y2 = getelementptr inbounds %struct.Pair, %struct.Pair* %p, i32 0, i32 1, !dbg !43
|
||||
store i32 %a, i32* %y2, align 4, !dbg !44
|
||||
br label %if.end, !dbg !45
|
||||
|
||||
if.else: ; preds = %entry
|
||||
%x3 = getelementptr inbounds %struct.Pair, %struct.Pair* %p, i32 0, i32 0, !dbg !46
|
||||
store i32 %b, i32* %x3, align 4, !dbg !48
|
||||
%y4 = getelementptr inbounds %struct.Pair, %struct.Pair* %p, i32 0, i32 1, !dbg !49
|
||||
store i32 0, i32* %y4, align 4, !dbg !50
|
||||
br label %if.end
|
||||
|
||||
if.end: ; preds = %if.else, %if.then
|
||||
%1 = bitcast %struct.Pair* %p to i8*, !dbg !51
|
||||
%2 = bitcast %struct.Pair* @pair to i8*, !dbg !51
|
||||
call void @llvm.memcpy.p0i8.p0i8.i64(i8* %2, i8* %1, i64 8, i32 4, i1 false), !dbg !51
|
||||
ret void
|
||||
}
|
||||
|
||||
; CHECK-LABEL: define void @if_else(i32 %cond, i32 %a, i32 %b)
|
||||
; CHECK: entry:
|
||||
; CHECK: call void @llvm.dbg.value(metadata i32 %a, metadata ![[PVAR:[0-9]+]], metadata ![[XFRAG:DIExpression\(DW_OP_LLVM_fragment, 0, 32\)]])
|
||||
; CHECK: call void @llvm.dbg.value(metadata i32 %b, metadata ![[PVAR]], metadata ![[YFRAG:DIExpression\(DW_OP_LLVM_fragment, 32, 32\)]])
|
||||
; CHECK: if.then:
|
||||
; CHECK: call void @llvm.dbg.value(metadata i32 0, metadata ![[PVAR]], metadata ![[XFRAG]])
|
||||
; CHECK: call void @llvm.dbg.value(metadata i32 %a, metadata ![[PVAR]], metadata ![[YFRAG]])
|
||||
; CHECK: if.else:
|
||||
; CHECK: call void @llvm.dbg.value(metadata i32 %b, metadata ![[PVAR]], metadata ![[XFRAG]])
|
||||
; CHECK: call void @llvm.dbg.value(metadata i32 0, metadata ![[PVAR]], metadata ![[YFRAG]])
|
||||
; CHECK: if.end:
|
||||
; CHECK: %p.sroa.4.0 = phi i32 [ %a, %if.then ], [ 0, %if.else ]
|
||||
; CHECK: %p.sroa.0.0 = phi i32 [ 0, %if.then ], [ %b, %if.else ]
|
||||
; CHECK: call void @llvm.dbg.value(metadata i32 %p.sroa.0.0, metadata ![[PVAR]], metadata ![[XFRAG]])
|
||||
; CHECK: call void @llvm.dbg.value(metadata i32 %p.sroa.4.0, metadata ![[PVAR]], metadata ![[YFRAG]])
|
||||
|
||||
; CHECK: ![[PVAR]] = !DILocalVariable(name: "p", {{.*}})
|
||||
|
||||
; Function Attrs: argmemonly nounwind
|
||||
declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture writeonly, i8* nocapture readonly, i64, i32, i1) #2
|
||||
|
||||
; Function Attrs: nounwind readnone speculatable
|
||||
declare void @llvm.dbg.addr(metadata, metadata, metadata)
|
||||
|
||||
!llvm.dbg.cu = !{!0}
|
||||
!llvm.module.flags = !{!3, !4, !5, !6}
|
||||
!llvm.ident = !{!7}
|
||||
|
||||
!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 6.0.0 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
|
||||
!1 = !DIFile(filename: "newvars.c", directory: "C:\5Csrc\5Cllvm-project\5Cbuild")
|
||||
!2 = !{}
|
||||
!3 = !{i32 2, !"Dwarf Version", i32 4}
|
||||
!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 6.0.0 "}
|
||||
!8 = distinct !DISubprogram(name: "if_else", scope: !1, file: !1, line: 2, type: !9, isLocal: false, isDefinition: true, scopeLine: 2, flags: DIFlagPrototyped, isOptimized: true, unit: !0, variables: !16)
|
||||
!9 = !DISubroutineType(types: !10)
|
||||
!10 = !{!11, !14, !14, !14}
|
||||
!11 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "Pair", file: !1, line: 1, size: 64, elements: !12)
|
||||
!12 = !{!13, !15}
|
||||
!13 = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: !11, file: !1, line: 1, baseType: !14, size: 32)
|
||||
!14 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
|
||||
!15 = !DIDerivedType(tag: DW_TAG_member, name: "y", scope: !11, file: !1, line: 1, baseType: !14, size: 32, offset: 32)
|
||||
!16 = !{!17, !18, !19, !20}
|
||||
!17 = !DILocalVariable(name: "b", arg: 3, scope: !8, file: !1, line: 2, type: !14)
|
||||
!18 = !DILocalVariable(name: "a", arg: 2, scope: !8, file: !1, line: 2, type: !14)
|
||||
!19 = !DILocalVariable(name: "cond", arg: 1, scope: !8, file: !1, line: 2, type: !14)
|
||||
!20 = !DILocalVariable(name: "p", scope: !8, file: !1, line: 3, type: !11)
|
||||
!22 = !DILocation(line: 2, column: 42, scope: !8)
|
||||
!23 = !DILocation(line: 2, column: 35, scope: !8)
|
||||
!24 = !DILocation(line: 2, column: 25, scope: !8)
|
||||
!25 = !DILocation(line: 3, column: 3, scope: !8)
|
||||
!26 = !DILocation(line: 3, column: 15, scope: !8)
|
||||
!27 = !DILocation(line: 4, column: 5, scope: !8)
|
||||
!28 = !DILocation(line: 4, column: 7, scope: !8)
|
||||
!29 = !{!30, !31, i64 0}
|
||||
!30 = !{!"Pair", !31, i64 0, !31, i64 4}
|
||||
!31 = !{!"int", !32, i64 0}
|
||||
!32 = !{!"omnipotent char", !33, i64 0}
|
||||
!33 = !{!"Simple C/C++ TBAA"}
|
||||
!34 = !DILocation(line: 5, column: 5, scope: !8)
|
||||
!35 = !DILocation(line: 5, column: 7, scope: !8)
|
||||
!36 = !{!30, !31, i64 4}
|
||||
!37 = !DILocation(line: 6, column: 7, scope: !38)
|
||||
!38 = distinct !DILexicalBlock(scope: !8, file: !1, line: 6, column: 7)
|
||||
!39 = !DILocation(line: 6, column: 7, scope: !8)
|
||||
!40 = !DILocation(line: 7, column: 7, scope: !41)
|
||||
!41 = distinct !DILexicalBlock(scope: !38, file: !1, line: 6, column: 13)
|
||||
!42 = !DILocation(line: 7, column: 9, scope: !41)
|
||||
!43 = !DILocation(line: 8, column: 7, scope: !41)
|
||||
!44 = !DILocation(line: 8, column: 9, scope: !41)
|
||||
!45 = !DILocation(line: 9, column: 3, scope: !41)
|
||||
!46 = !DILocation(line: 10, column: 7, scope: !47)
|
||||
!47 = distinct !DILexicalBlock(scope: !38, file: !1, line: 9, column: 10)
|
||||
!48 = !DILocation(line: 10, column: 9, scope: !47)
|
||||
!49 = !DILocation(line: 11, column: 7, scope: !47)
|
||||
!50 = !DILocation(line: 11, column: 9, scope: !47)
|
||||
!51 = !DILocation(line: 13, column: 10, scope: !8)
|
||||
!52 = !{i64 0, i64 4, !53, i64 4, i64 4, !53}
|
||||
!53 = !{!31, !31, i64 0}
|
||||
!54 = !DILocation(line: 14, column: 1, scope: !8)
|
|
@ -1,5 +1,6 @@
|
|||
set(LLVM_LINK_COMPONENTS
|
||||
Analysis
|
||||
AsmParser
|
||||
Core
|
||||
Support
|
||||
TransformUtils
|
||||
|
|
|
@ -8,10 +8,14 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Transforms/Utils/Local.h"
|
||||
#include "llvm/AsmParser/Parser.h"
|
||||
#include "llvm/IR/BasicBlock.h"
|
||||
#include "llvm/IR/DIBuilder.h"
|
||||
#include "llvm/IR/IRBuilder.h"
|
||||
#include "llvm/IR/Instructions.h"
|
||||
#include "llvm/IR/IntrinsicInst.h"
|
||||
#include "llvm/IR/LLVMContext.h"
|
||||
#include "llvm/Support/SourceMgr.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
@ -95,3 +99,70 @@ TEST(Local, RemoveDuplicatePHINodes) {
|
|||
EXPECT_TRUE(EliminateDuplicatePHINodes(BB));
|
||||
EXPECT_EQ(3U, BB->size());
|
||||
}
|
||||
|
||||
std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) {
|
||||
SMDiagnostic Err;
|
||||
std::unique_ptr<Module> Mod = parseAssemblyString(IR, Err, C);
|
||||
if (!Mod)
|
||||
Err.print("UtilsTests", errs());
|
||||
return Mod;
|
||||
}
|
||||
|
||||
TEST(Local, ReplaceDbgDeclare) {
|
||||
LLVMContext C;
|
||||
|
||||
// Original C source to get debug info for a local variable:
|
||||
// void f() { int x; }
|
||||
std::unique_ptr<Module> M = parseIR(
|
||||
C,
|
||||
"define void @f() !dbg !8 {\n"
|
||||
"entry:\n"
|
||||
" %x = alloca i32, align 4\n"
|
||||
" call void @llvm.dbg.declare(metadata i32* %x, metadata !11, metadata "
|
||||
"!DIExpression()), !dbg !13\n"
|
||||
" call void @llvm.dbg.declare(metadata i32* %x, metadata !11, metadata "
|
||||
"!DIExpression()), !dbg !13\n"
|
||||
" ret void, !dbg !14\n"
|
||||
"}\n"
|
||||
"declare void @llvm.dbg.declare(metadata, metadata, metadata)\n"
|
||||
"!llvm.dbg.cu = !{!0}\n"
|
||||
"!llvm.module.flags = !{!3, !4}\n"
|
||||
"!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "
|
||||
"\"clang version 6.0.0 \", isOptimized: false, runtimeVersion: 0, "
|
||||
"emissionKind: FullDebug, enums: !2)\n"
|
||||
"!1 = !DIFile(filename: \"t2.c\", directory: \"foo\")\n"
|
||||
"!2 = !{}\n"
|
||||
"!3 = !{i32 2, !\"Dwarf Version\", i32 4}\n"
|
||||
"!4 = !{i32 2, !\"Debug Info Version\", i32 3}\n"
|
||||
"!8 = distinct !DISubprogram(name: \"f\", scope: !1, file: !1, line: 1, "
|
||||
"type: !9, isLocal: false, isDefinition: true, scopeLine: 1, "
|
||||
"isOptimized: false, unit: !0, variables: !2)\n"
|
||||
"!9 = !DISubroutineType(types: !10)\n"
|
||||
"!10 = !{null}\n"
|
||||
"!11 = !DILocalVariable(name: \"x\", scope: !8, file: !1, line: 2, type: "
|
||||
"!12)\n"
|
||||
"!12 = !DIBasicType(name: \"int\", size: 32, encoding: DW_ATE_signed)\n"
|
||||
"!13 = !DILocation(line: 2, column: 7, scope: !8)\n"
|
||||
"!14 = !DILocation(line: 3, column: 1, scope: !8)\n");
|
||||
auto *GV = M->getNamedValue("f");
|
||||
ASSERT_TRUE(GV);
|
||||
auto *F = dyn_cast<Function>(GV);
|
||||
ASSERT_TRUE(F);
|
||||
Instruction *Inst = &F->front().front();
|
||||
auto *AI = dyn_cast<AllocaInst>(Inst);
|
||||
ASSERT_TRUE(AI);
|
||||
Inst = Inst->getNextNode()->getNextNode();
|
||||
ASSERT_TRUE(Inst);
|
||||
auto *DII = dyn_cast<DbgDeclareInst>(Inst);
|
||||
ASSERT_TRUE(DII);
|
||||
Value *NewBase = Constant::getNullValue(Type::getInt32PtrTy(C));
|
||||
DIBuilder DIB(*M);
|
||||
replaceDbgDeclare(AI, NewBase, DII, DIB, /*Deref=*/false, /*Offset=*/0);
|
||||
|
||||
// There should be exactly two dbg.declares.
|
||||
int Declares = 0;
|
||||
for (const Instruction &I : F->front())
|
||||
if (isa<DbgDeclareInst>(I))
|
||||
Declares++;
|
||||
EXPECT_EQ(2, Declares);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue