1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-10-18 18:42:46 +02:00

Revert r313825: "[IR] Add llvm.dbg.addr, a control-dependent version of llvm.dbg.declare"

.. as well as the two subsequent changes r313826 and r313875.

This leads to segfaults in combination with ASAN. Will forward repro
instructions to the original author (rnk).

llvm-svn: 313876
This commit is contained in:
Daniel Jasper 2017-09-21 12:07:33 +00:00
parent 2e96ed2e60
commit 9eea6fd83b
18 changed files with 140 additions and 782 deletions

View File

@ -171,48 +171,7 @@ Debugger intrinsic functions
---------------------------- ----------------------------
LLVM uses several intrinsic functions (name prefixed with "``llvm.dbg``") to LLVM uses several intrinsic functions (name prefixed with "``llvm.dbg``") to
track source local variables through optimization and code generation. provide debug information at various points in generated code.
``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`` ``llvm.dbg.declare``
^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^
@ -221,14 +180,26 @@ concrete source variable must agree on the memory location.
void @llvm.dbg.declare(metadata, metadata, metadata) void @llvm.dbg.declare(metadata, metadata, metadata)
This intrinsic is identical to `llvm.dbg.addr`, except that there can only be This intrinsic provides information about a local element (e.g., variable). The
one call to `llvm.dbg.declare` for a given concrete `local variable first argument is metadata holding the alloca for the variable. The second
<LangRef.html#dilocalvariable>`_. It is not control-dependent, meaning that if argument is a `local variable <LangRef.html#dilocalvariable>`_ containing a
a call to `llvm.dbg.declare` exists and has a valid location argument, that description of the variable. The third argument is a `complex expression
address is considered to be the true home of the variable across its entire <LangRef.html#diexpression>`_. An `llvm.dbg.declare` instrinsic describes the
lifetime. This makes it hard for optimizations to preserve accurate debug info *location* of a source variable.
in the presence of ``llvm.dbg.declare``, so we are transitioning away from it,
and we plan to deprecate it in future LLVM releases. .. 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)
``llvm.dbg.value`` ``llvm.dbg.value``
@ -271,9 +242,6 @@ following C fragment, for example:
8. X = Y; 8. X = Y;
9. } 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: Compiled to LLVM, this function would be represented like this:
.. code-block:: text .. code-block:: text

View File

@ -71,12 +71,6 @@ namespace llvm {
/// variable's value or its address. /// variable's value or its address.
Value *getVariableLocation(bool AllowNullOp = true) const; 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 { DILocalVariable *getVariable() const {
return cast<DILocalVariable>(getRawVariable()); return cast<DILocalVariable>(getRawVariable());
} }
@ -93,13 +87,11 @@ namespace llvm {
return cast<MetadataAsValue>(getArgOperand(2))->getMetadata(); return cast<MetadataAsValue>(getArgOperand(2))->getMetadata();
} }
/// \name Casting methods // Methods for support type inquiry through isa, cast, and dyn_cast:
/// @{
static bool classof(const IntrinsicInst *I) { static bool classof(const IntrinsicInst *I) {
switch (I->getIntrinsicID()) { switch (I->getIntrinsicID()) {
case Intrinsic::dbg_declare: case Intrinsic::dbg_declare:
case Intrinsic::dbg_value: case Intrinsic::dbg_value:
case Intrinsic::dbg_addr:
return true; return true;
default: return false; default: return false;
} }
@ -107,7 +99,6 @@ namespace llvm {
static bool classof(const Value *V) { static bool classof(const Value *V) {
return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V)); return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
} }
/// @}
}; };
/// This represents the llvm.dbg.declare instruction. /// This represents the llvm.dbg.declare instruction.
@ -115,30 +106,13 @@ namespace llvm {
public: public:
Value *getAddress() const { return getVariableLocation(); } Value *getAddress() const { return getVariableLocation(); }
/// \name Casting methods // Methods for support type inquiry through isa, cast, and dyn_cast:
/// @{
static bool classof(const IntrinsicInst *I) { static bool classof(const IntrinsicInst *I) {
return I->getIntrinsicID() == Intrinsic::dbg_declare; return I->getIntrinsicID() == Intrinsic::dbg_declare;
} }
static bool classof(const Value *V) { static bool classof(const Value *V) {
return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(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. /// This represents the llvm.dbg.value instruction.
@ -148,15 +122,13 @@ namespace llvm {
return getVariableLocation(/* AllowNullOp = */ false); return getVariableLocation(/* AllowNullOp = */ false);
} }
/// \name Casting methods // Methods for support type inquiry through isa, cast, and dyn_cast:
/// @{
static bool classof(const IntrinsicInst *I) { static bool classof(const IntrinsicInst *I) {
return I->getIntrinsicID() == Intrinsic::dbg_value; return I->getIntrinsicID() == Intrinsic::dbg_value;
} }
static bool classof(const Value *V) { static bool classof(const Value *V) {
return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V)); return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
} }
/// @}
}; };
/// This is the common base class for constrained floating point intrinsics. /// This is the common base class for constrained floating point intrinsics.

View File

@ -583,16 +583,12 @@ let IntrProperties = [IntrNoMem, IntrSpeculatable] in {
let IntrProperties = [IntrNoMem, IntrSpeculatable] in { let IntrProperties = [IntrNoMem, IntrSpeculatable] in {
def int_dbg_declare : Intrinsic<[], def int_dbg_declare : Intrinsic<[],
[llvm_metadata_ty, [llvm_metadata_ty,
llvm_metadata_ty, llvm_metadata_ty,
llvm_metadata_ty]>; llvm_metadata_ty]>;
def int_dbg_value : Intrinsic<[], def int_dbg_value : Intrinsic<[],
[llvm_metadata_ty, [llvm_metadata_ty,
llvm_metadata_ty, 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----------------------===// //===------------------ Exception Handling Intrinsics----------------------===//

View File

@ -16,7 +16,6 @@
#define LLVM_TRANSFORMS_UTILS_LOCAL_H #define LLVM_TRANSFORMS_UTILS_LOCAL_H
#include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/TinyPtrVector.h"
#include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/IR/DataLayout.h" #include "llvm/IR/DataLayout.h"
#include "llvm/IR/Dominators.h" #include "llvm/IR/Dominators.h"
@ -33,7 +32,6 @@ class BranchInst;
class Instruction; class Instruction;
class CallInst; class CallInst;
class DbgDeclareInst; class DbgDeclareInst;
class DbgInfoIntrinsic;
class DbgValueInst; class DbgValueInst;
class StoreInst; class StoreInst;
class LoadInst; class LoadInst;
@ -264,28 +262,26 @@ Value *EmitGEPOffset(IRBuilderTy *Builder, const DataLayout &DL, User *GEP,
/// ///
/// Inserts a llvm.dbg.value intrinsic before a store to an alloca'd value /// Inserts a llvm.dbg.value intrinsic before a store to an alloca'd value
/// that has an associated llvm.dbg.declare or llvm.dbg.addr intrinsic. /// that has an associated llvm.dbg.decl intrinsic.
void ConvertDebugDeclareToDebugValue(DbgInfoIntrinsic *DII, void ConvertDebugDeclareToDebugValue(DbgDeclareInst *DDI,
StoreInst *SI, DIBuilder &Builder); StoreInst *SI, DIBuilder &Builder);
/// Inserts a llvm.dbg.value intrinsic before a load of an alloca'd value /// Inserts a llvm.dbg.value intrinsic before a load of an alloca'd value
/// that has an associated llvm.dbg.declare or llvm.dbg.addr intrinsic. /// that has an associated llvm.dbg.decl intrinsic.
void ConvertDebugDeclareToDebugValue(DbgInfoIntrinsic *DII, void ConvertDebugDeclareToDebugValue(DbgDeclareInst *DDI,
LoadInst *LI, DIBuilder &Builder); LoadInst *LI, DIBuilder &Builder);
/// Inserts a llvm.dbg.value intrinsic after a phi that has an associated /// Inserts a llvm.dbg.value intrinsic after a phi of an alloca'd value
/// llvm.dbg.declare or llvm.dbg.addr intrinsic. /// that has an associated llvm.dbg.decl intrinsic.
void ConvertDebugDeclareToDebugValue(DbgInfoIntrinsic *DII, void ConvertDebugDeclareToDebugValue(DbgDeclareInst *DDI,
PHINode *LI, DIBuilder &Builder); PHINode *LI, DIBuilder &Builder);
/// Lowers llvm.dbg.declare intrinsics into appropriate set of /// Lowers llvm.dbg.declare intrinsics into appropriate set of
/// llvm.dbg.value intrinsics. /// llvm.dbg.value intrinsics.
bool LowerDbgDeclare(Function &F); bool LowerDbgDeclare(Function &F);
/// Finds all intrinsics declaring local variables as living in the memory that /// Finds the llvm.dbg.declare intrinsic corresponding to an alloca, if any.
/// 'V' points to. This may include a mix of dbg.declare and DbgDeclareInst *FindAllocaDbgDeclare(Value *V);
/// dbg.addr intrinsics.
TinyPtrVector<DbgInfoIntrinsic *> FindDbgAddrUses(Value *V);
/// Finds the llvm.dbg.value intrinsics describing a value. /// Finds the llvm.dbg.value intrinsics describing a value.
void findDbgValues(SmallVectorImpl<DbgValueInst *> &DbgValues, Value *V); void findDbgValues(SmallVectorImpl<DbgValueInst *> &DbgValues, Value *V);

View File

@ -5109,48 +5109,37 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) {
DAG.setRoot(CallResult.second); DAG.setRoot(CallResult.second);
return nullptr; return nullptr;
} }
case Intrinsic::dbg_addr:
case Intrinsic::dbg_declare: { case Intrinsic::dbg_declare: {
const DbgInfoIntrinsic &DI = cast<DbgInfoIntrinsic>(I); const DbgDeclareInst &DI = cast<DbgDeclareInst>(I);
DILocalVariable *Variable = DI.getVariable(); DILocalVariable *Variable = DI.getVariable();
DIExpression *Expression = DI.getExpression(); DIExpression *Expression = DI.getExpression();
const Value *Address = DI.getAddress();
assert(Variable && "Missing variable"); assert(Variable && "Missing variable");
if (!Address) {
DEBUG(dbgs() << "Dropping debug info for " << DI << "\n");
return nullptr;
}
// Check if address has undef value. // Check if address has undef value.
const Value *Address = DI.getVariableLocation(); if (isa<UndefValue>(Address) ||
if (!Address || isa<UndefValue>(Address) ||
(Address->use_empty() && !isa<Argument>(Address))) { (Address->use_empty() && !isa<Argument>(Address))) {
DEBUG(dbgs() << "Dropping debug info for " << DI << "\n"); DEBUG(dbgs() << "Dropping debug info for " << DI << "\n");
return nullptr; return nullptr;
} }
bool isParameter = Variable->isParameter() || isa<Argument>(Address); // Static allocas are handled more efficiently in the variable frame index
// side table.
// 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 = if (const auto *AI =
dyn_cast<AllocaInst>(Address->stripInBoundsConstantOffsets())) { dyn_cast<AllocaInst>(Address->stripInBoundsConstantOffsets()))
if (AI->isStaticAlloca()) { if (AI->isStaticAlloca() && FuncInfo.StaticAllocaMap.count(AI))
auto I = FuncInfo.StaticAllocaMap.find(AI); return nullptr;
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 // Byval arguments with frame indices were already handled after argument
// DBG_VALUE instructions. llvm.dbg.declare is handled as a frame index in // lowering and before isel.
// the MachineFunction variable table. if (const auto *Arg =
if (FI != INT_MAX) { dyn_cast<Argument>(Address->stripInBoundsConstantOffsets()))
if (Intrinsic == Intrinsic::dbg_addr) if (FuncInfo.getArgumentFrameIndex(Arg) != INT_MAX)
DAG.AddDbgValue(DAG.getFrameIndexDbgValue(Variable, Expression, FI, dl, return nullptr;
SDNodeOrder),
getRoot().getNode(), isParameter);
return nullptr;
}
SDValue &N = NodeMap[Address]; SDValue &N = NodeMap[Address];
if (!N.getNode() && isa<Argument>(Address)) if (!N.getNode() && isa<Argument>(Address))
@ -5161,6 +5150,7 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) {
if (const BitCastInst *BCI = dyn_cast<BitCastInst>(Address)) if (const BitCastInst *BCI = dyn_cast<BitCastInst>(Address))
Address = BCI->getOperand(0); Address = BCI->getOperand(0);
// Parameters are handled specially. // Parameters are handled specially.
bool isParameter = Variable->isParameter() || isa<Argument>(Address);
auto FINode = dyn_cast<FrameIndexSDNode>(N.getNode()); auto FINode = dyn_cast<FrameIndexSDNode>(N.getNode());
if (isParameter && FINode) { if (isParameter && FINode) {
// Byval parameter. We have a frame index at this point. // Byval parameter. We have a frame index at this point.

View File

@ -24,11 +24,6 @@
using namespace llvm; using namespace llvm;
using namespace llvm::dwarf; 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) DIBuilder::DIBuilder(Module &m, bool AllowUnresolvedNodes)
: M(m), VMContext(M.getContext()), CUNode(nullptr), : M(m), VMContext(M.getContext()), CUNode(nullptr),
DeclareFn(nullptr), ValueFn(nullptr), DeclareFn(nullptr), ValueFn(nullptr),
@ -781,11 +776,6 @@ static Instruction *withDebugLoc(Instruction *I, const DILocation *DL) {
return I; 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, Instruction *DIBuilder::insertDeclare(Value *Storage, DILocalVariable *VarInfo,
DIExpression *Expr, const DILocation *DL, DIExpression *Expr, const DILocation *DL,
Instruction *InsertBefore) { Instruction *InsertBefore) {
@ -795,7 +785,7 @@ Instruction *DIBuilder::insertDeclare(Value *Storage, DILocalVariable *VarInfo,
VarInfo->getScope()->getSubprogram() && VarInfo->getScope()->getSubprogram() &&
"Expected matching subprograms"); "Expected matching subprograms");
if (!DeclareFn) if (!DeclareFn)
DeclareFn = getDeclareIntrin(M); DeclareFn = Intrinsic::getDeclaration(&M, Intrinsic::dbg_declare);
trackIfUnresolved(VarInfo); trackIfUnresolved(VarInfo);
trackIfUnresolved(Expr); trackIfUnresolved(Expr);
@ -814,7 +804,7 @@ Instruction *DIBuilder::insertDeclare(Value *Storage, DILocalVariable *VarInfo,
VarInfo->getScope()->getSubprogram() && VarInfo->getScope()->getSubprogram() &&
"Expected matching subprograms"); "Expected matching subprograms");
if (!DeclareFn) if (!DeclareFn)
DeclareFn = getDeclareIntrin(M); DeclareFn = Intrinsic::getDeclaration(&M, Intrinsic::dbg_declare);
trackIfUnresolved(VarInfo); trackIfUnresolved(VarInfo);
trackIfUnresolved(Expr); trackIfUnresolved(Expr);

View File

@ -4001,8 +4001,6 @@ void Verifier::visitIntrinsicCallSite(Intrinsic::ID ID, CallSite CS) {
"invalid llvm.dbg.declare intrinsic call 1", CS); "invalid llvm.dbg.declare intrinsic call 1", CS);
visitDbgIntrinsic("declare", cast<DbgInfoIntrinsic>(*CS.getInstruction())); visitDbgIntrinsic("declare", cast<DbgInfoIntrinsic>(*CS.getInstruction()));
break; break;
case Intrinsic::dbg_addr: // llvm.dbg.addr
visitDbgIntrinsic("addr", cast<DbgInfoIntrinsic>(*CS.getInstruction()));
case Intrinsic::dbg_value: // llvm.dbg.value case Intrinsic::dbg_value: // llvm.dbg.value
visitDbgIntrinsic("value", cast<DbgInfoIntrinsic>(*CS.getInstruction())); visitDbgIntrinsic("value", cast<DbgInfoIntrinsic>(*CS.getInstruction()));
break; break;

View File

@ -2106,10 +2106,10 @@ Instruction *InstCombiner::visitAllocSite(Instruction &MI) {
// If we are removing an alloca with a dbg.declare, insert dbg.value calls // If we are removing an alloca with a dbg.declare, insert dbg.value calls
// before each store. // before each store.
TinyPtrVector<DbgInfoIntrinsic *> DIIs; DbgDeclareInst *DDI = nullptr;
std::unique_ptr<DIBuilder> DIB; std::unique_ptr<DIBuilder> DIB;
if (isa<AllocaInst>(MI)) { if (isa<AllocaInst>(MI)) {
DIIs = FindDbgAddrUses(&MI); DDI = FindAllocaDbgDeclare(&MI);
DIB.reset(new DIBuilder(*MI.getModule(), /*AllowUnresolved=*/false)); DIB.reset(new DIBuilder(*MI.getModule(), /*AllowUnresolved=*/false));
} }
@ -2145,9 +2145,8 @@ Instruction *InstCombiner::visitAllocSite(Instruction &MI) {
} else if (isa<BitCastInst>(I) || isa<GetElementPtrInst>(I) || } else if (isa<BitCastInst>(I) || isa<GetElementPtrInst>(I) ||
isa<AddrSpaceCastInst>(I)) { isa<AddrSpaceCastInst>(I)) {
replaceInstUsesWith(*I, UndefValue::get(I->getType())); replaceInstUsesWith(*I, UndefValue::get(I->getType()));
} else if (auto *SI = dyn_cast<StoreInst>(I)) { } else if (DDI && isa<StoreInst>(I)) {
for (auto *DII : DIIs) ConvertDebugDeclareToDebugValue(DDI, cast<StoreInst>(I), *DIB);
ConvertDebugDeclareToDebugValue(DII, SI, *DIB);
} }
eraseInstFromFunction(*I); eraseInstFromFunction(*I);
} }
@ -2160,8 +2159,8 @@ Instruction *InstCombiner::visitAllocSite(Instruction &MI) {
None, "", II->getParent()); None, "", II->getParent());
} }
for (auto *DII : DIIs) if (DDI)
eraseInstFromFunction(*DII); eraseInstFromFunction(*DDI);
return eraseInstFromFunction(MI); return eraseInstFromFunction(MI);
} }

View File

@ -4102,10 +4102,9 @@ bool SROA::splitAlloca(AllocaInst &AI, AllocaSlices &AS) {
// Migrate debug information from the old alloca to the new alloca(s) // Migrate debug information from the old alloca to the new alloca(s)
// and the individual partitions. // and the individual partitions.
TinyPtrVector<DbgInfoIntrinsic *> DbgDeclares = FindDbgAddrUses(&AI); if (DbgDeclareInst *DbgDecl = FindAllocaDbgDeclare(&AI)) {
if (!DbgDeclares.empty()) { auto *Var = DbgDecl->getVariable();
auto *Var = DbgDeclares.front()->getVariable(); auto *Expr = DbgDecl->getExpression();
auto *Expr = DbgDeclares.front()->getExpression();
DIBuilder DIB(*AI.getModule(), /*AllowUnresolved*/ false); DIBuilder DIB(*AI.getModule(), /*AllowUnresolved*/ false);
uint64_t AllocaSize = DL.getTypeSizeInBits(AI.getAllocatedType()); uint64_t AllocaSize = DL.getTypeSizeInBits(AI.getAllocatedType());
for (auto Fragment : Fragments) { for (auto Fragment : Fragments) {
@ -4137,12 +4136,12 @@ bool SROA::splitAlloca(AllocaInst &AI, AllocaSlices &AS) {
DIExpression::createFragmentExpression(Expr, Start, Size); DIExpression::createFragmentExpression(Expr, Start, Size);
} }
// Remove any existing intrinsics describing the same alloca. // Remove any existing dbg.declare intrinsic describing the same alloca.
for (DbgInfoIntrinsic *OldDII : FindDbgAddrUses(Fragment.Alloca)) if (DbgDeclareInst *OldDDI = FindAllocaDbgDeclare(Fragment.Alloca))
OldDII->eraseFromParent(); OldDDI->eraseFromParent();
DIB.insertDeclare(Fragment.Alloca, Var, FragmentExpr, DIB.insertDeclare(Fragment.Alloca, Var, FragmentExpr,
DbgDeclares.front()->getDebugLoc(), &AI); DbgDecl->getDebugLoc(), &AI);
} }
} }
return Changed; return Changed;
@ -4247,15 +4246,6 @@ void SROA::deleteDeadInstructions(
Instruction *I = DeadInsts.pop_back_val(); Instruction *I = DeadInsts.pop_back_val();
DEBUG(dbgs() << "Deleting dead instruction: " << *I << "\n"); 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())); I->replaceAllUsesWith(UndefValue::get(I->getType()));
for (Use &Operand : I->operands()) for (Use &Operand : I->operands())
@ -4266,6 +4256,12 @@ void SROA::deleteDeadInstructions(
DeadInsts.insert(U); DeadInsts.insert(U);
} }
if (AllocaInst *AI = dyn_cast<AllocaInst>(I)) {
DeletedAllocas.insert(AI);
if (DbgDeclareInst *DbgDecl = FindAllocaDbgDeclare(AI))
DbgDecl->eraseFromParent();
}
++NumDeleted; ++NumDeleted;
I->eraseFromParent(); I->eraseFromParent();
} }

View File

@ -1098,13 +1098,12 @@ static bool PhiHasDebugValue(DILocalVariable *DIVar,
} }
/// Inserts a llvm.dbg.value intrinsic before a store to an alloca'd value /// Inserts a llvm.dbg.value intrinsic before a store to an alloca'd value
/// that has an associated llvm.dbg.declare or llvm.dbg.addr intrinsic. /// that has an associated llvm.dbg.decl intrinsic.
void llvm::ConvertDebugDeclareToDebugValue(DbgInfoIntrinsic *DII, void llvm::ConvertDebugDeclareToDebugValue(DbgDeclareInst *DDI,
StoreInst *SI, DIBuilder &Builder) { StoreInst *SI, DIBuilder &Builder) {
assert(DII->isAddressOfVariable()); auto *DIVar = DDI->getVariable();
auto *DIVar = DII->getVariable();
assert(DIVar && "Missing variable"); assert(DIVar && "Missing variable");
auto *DIExpr = DII->getExpression(); auto *DIExpr = DDI->getExpression();
Value *DV = SI->getOperand(0); Value *DV = SI->getOperand(0);
// If an argument is zero extended then use argument directly. The ZExt // If an argument is zero extended then use argument directly. The ZExt
@ -1115,7 +1114,7 @@ void llvm::ConvertDebugDeclareToDebugValue(DbgInfoIntrinsic *DII,
if (SExtInst *SExt = dyn_cast<SExtInst>(SI->getOperand(0))) if (SExtInst *SExt = dyn_cast<SExtInst>(SI->getOperand(0)))
ExtendedArg = dyn_cast<Argument>(SExt->getOperand(0)); ExtendedArg = dyn_cast<Argument>(SExt->getOperand(0));
if (ExtendedArg) { if (ExtendedArg) {
// If this DII was already describing only a fragment of a variable, ensure // If this DDI was already describing only a fragment of a variable, ensure
// that fragment is appropriately narrowed here. // that fragment is appropriately narrowed here.
// But if a fragment wasn't used, describe the value as the original // 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 // argument (rather than the zext or sext) so that it remains described even
@ -1128,23 +1127,23 @@ void llvm::ConvertDebugDeclareToDebugValue(DbgInfoIntrinsic *DII,
DIExpr->elements_end() - 3); DIExpr->elements_end() - 3);
Ops.push_back(dwarf::DW_OP_LLVM_fragment); Ops.push_back(dwarf::DW_OP_LLVM_fragment);
Ops.push_back(FragmentOffset); Ops.push_back(FragmentOffset);
const DataLayout &DL = DII->getModule()->getDataLayout(); const DataLayout &DL = DDI->getModule()->getDataLayout();
Ops.push_back(DL.getTypeSizeInBits(ExtendedArg->getType())); Ops.push_back(DL.getTypeSizeInBits(ExtendedArg->getType()));
DIExpr = Builder.createExpression(Ops); DIExpr = Builder.createExpression(Ops);
} }
DV = ExtendedArg; DV = ExtendedArg;
} }
if (!LdStHasDebugValue(DIVar, DIExpr, SI)) if (!LdStHasDebugValue(DIVar, DIExpr, SI))
Builder.insertDbgValueIntrinsic(DV, DIVar, DIExpr, DII->getDebugLoc(), Builder.insertDbgValueIntrinsic(DV, DIVar, DIExpr, DDI->getDebugLoc(),
SI); SI);
} }
/// Inserts a llvm.dbg.value intrinsic before a load of an alloca'd value /// Inserts a llvm.dbg.value intrinsic before a load of an alloca'd value
/// that has an associated llvm.dbg.declare or llvm.dbg.addr intrinsic. /// that has an associated llvm.dbg.decl intrinsic.
void llvm::ConvertDebugDeclareToDebugValue(DbgInfoIntrinsic *DII, void llvm::ConvertDebugDeclareToDebugValue(DbgDeclareInst *DDI,
LoadInst *LI, DIBuilder &Builder) { LoadInst *LI, DIBuilder &Builder) {
auto *DIVar = DII->getVariable(); auto *DIVar = DDI->getVariable();
auto *DIExpr = DII->getExpression(); auto *DIExpr = DDI->getExpression();
assert(DIVar && "Missing variable"); assert(DIVar && "Missing variable");
if (LdStHasDebugValue(DIVar, DIExpr, LI)) if (LdStHasDebugValue(DIVar, DIExpr, LI))
@ -1155,16 +1154,16 @@ void llvm::ConvertDebugDeclareToDebugValue(DbgInfoIntrinsic *DII,
// preferable to keep tracking both the loaded value and the original // preferable to keep tracking both the loaded value and the original
// address in case the alloca can not be elided. // address in case the alloca can not be elided.
Instruction *DbgValue = Builder.insertDbgValueIntrinsic( Instruction *DbgValue = Builder.insertDbgValueIntrinsic(
LI, DIVar, DIExpr, DII->getDebugLoc(), (Instruction *)nullptr); LI, DIVar, DIExpr, DDI->getDebugLoc(), (Instruction *)nullptr);
DbgValue->insertAfter(LI); DbgValue->insertAfter(LI);
} }
/// Inserts a llvm.dbg.value intrinsic after a phi that has an associated /// Inserts a llvm.dbg.value intrinsic after a phi
/// llvm.dbg.declare or llvm.dbg.addr intrinsic. /// that has an associated llvm.dbg.decl intrinsic.
void llvm::ConvertDebugDeclareToDebugValue(DbgInfoIntrinsic *DII, void llvm::ConvertDebugDeclareToDebugValue(DbgDeclareInst *DDI,
PHINode *APN, DIBuilder &Builder) { PHINode *APN, DIBuilder &Builder) {
auto *DIVar = DII->getVariable(); auto *DIVar = DDI->getVariable();
auto *DIExpr = DII->getExpression(); auto *DIExpr = DDI->getExpression();
assert(DIVar && "Missing variable"); assert(DIVar && "Missing variable");
if (PhiHasDebugValue(DIVar, DIExpr, APN)) if (PhiHasDebugValue(DIVar, DIExpr, APN))
@ -1177,7 +1176,7 @@ void llvm::ConvertDebugDeclareToDebugValue(DbgInfoIntrinsic *DII,
// insertion point. // insertion point.
// FIXME: Insert dbg.value markers in the successors when appropriate. // FIXME: Insert dbg.value markers in the successors when appropriate.
if (InsertionPt != BB->end()) if (InsertionPt != BB->end())
Builder.insertDbgValueIntrinsic(APN, DIVar, DIExpr, DII->getDebugLoc(), Builder.insertDbgValueIntrinsic(APN, DIVar, DIExpr, DDI->getDebugLoc(),
&*InsertionPt); &*InsertionPt);
} }
@ -1232,25 +1231,16 @@ bool llvm::LowerDbgDeclare(Function &F) {
return true; return true;
} }
/// Finds all intrinsics declaring local variables as living in the memory that /// FindAllocaDbgDeclare - Finds the llvm.dbg.declare intrinsic describing the
/// 'V' points to. This may include a mix of dbg.declare and /// alloca 'V', if any.
/// dbg.addr intrinsics. DbgDeclareInst *llvm::FindAllocaDbgDeclare(Value *V) {
TinyPtrVector<DbgInfoIntrinsic *> llvm::FindDbgAddrUses(Value *V) { if (auto *L = LocalAsMetadata::getIfExists(V))
auto *L = LocalAsMetadata::getIfExists(V); if (auto *MDV = MetadataAsValue::getIfExists(V->getContext(), L))
if (!L) for (User *U : MDV->users())
return {}; if (DbgDeclareInst *DDI = dyn_cast<DbgDeclareInst>(U))
auto *MDV = MetadataAsValue::getIfExists(V->getContext(), L); return DDI;
if (!MDV)
return {};
TinyPtrVector<DbgInfoIntrinsic *> Declares; return nullptr;
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) { void llvm::findDbgValues(SmallVectorImpl<DbgValueInst *> &DbgValues, Value *V) {
@ -1261,22 +1251,23 @@ void llvm::findDbgValues(SmallVectorImpl<DbgValueInst *> &DbgValues, Value *V) {
DbgValues.push_back(DVI); DbgValues.push_back(DVI);
} }
bool llvm::replaceDbgDeclare(Value *Address, Value *NewAddress, bool llvm::replaceDbgDeclare(Value *Address, Value *NewAddress,
Instruction *InsertBefore, DIBuilder &Builder, Instruction *InsertBefore, DIBuilder &Builder,
bool Deref, int Offset) { bool Deref, int Offset) {
auto DbgAddrs = FindDbgAddrUses(Address); DbgDeclareInst *DDI = FindAllocaDbgDeclare(Address);
for (DbgInfoIntrinsic *DII : DbgAddrs) { if (!DDI)
DebugLoc Loc = DII->getDebugLoc(); return false;
auto *DIVar = DII->getVariable(); DebugLoc Loc = DDI->getDebugLoc();
auto *DIExpr = DII->getExpression(); auto *DIVar = DDI->getVariable();
assert(DIVar && "Missing variable"); auto *DIExpr = DDI->getExpression();
DIExpr = DIExpression::prepend(DIExpr, Deref, Offset); assert(DIVar && "Missing variable");
// Insert llvm.dbg.declare immediately after the original alloca, and remove DIExpr = DIExpression::prepend(DIExpr, Deref, Offset);
// old llvm.dbg.declare. // Insert llvm.dbg.declare immediately after the original alloca, and remove
Builder.insertDeclare(NewAddress, DIVar, DIExpr, Loc, InsertBefore); // old llvm.dbg.declare.
DII->eraseFromParent(); Builder.insertDeclare(NewAddress, DIVar, DIExpr, Loc, InsertBefore);
} DDI->eraseFromParent();
return !DbgAddrs.empty(); return true;
} }
bool llvm::replaceDbgDeclareForAlloca(AllocaInst *AI, Value *NewAllocaAddress, bool llvm::replaceDbgDeclareForAlloca(AllocaInst *AI, Value *NewAllocaAddress,

View File

@ -103,7 +103,7 @@ struct AllocaInfo {
bool OnlyUsedInOneBlock; bool OnlyUsedInOneBlock;
Value *AllocaPointerVal; Value *AllocaPointerVal;
TinyPtrVector<DbgInfoIntrinsic*> DbgDeclares; DbgDeclareInst *DbgDeclare;
void clear() { void clear() {
DefiningBlocks.clear(); DefiningBlocks.clear();
@ -112,7 +112,7 @@ struct AllocaInfo {
OnlyBlock = nullptr; OnlyBlock = nullptr;
OnlyUsedInOneBlock = true; OnlyUsedInOneBlock = true;
AllocaPointerVal = nullptr; AllocaPointerVal = nullptr;
DbgDeclares.clear(); DbgDeclare = nullptr;
} }
/// Scan the uses of the specified alloca, filling in the AllocaInfo used /// Scan the uses of the specified alloca, filling in the AllocaInfo used
@ -147,7 +147,7 @@ struct AllocaInfo {
} }
} }
DbgDeclares = FindDbgAddrUses(AI); DbgDeclare = FindAllocaDbgDeclare(AI);
} }
}; };
@ -245,7 +245,7 @@ struct PromoteMem2Reg {
/// For each alloca, we keep track of the dbg.declare intrinsic that /// 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 /// describes it, if any, so that we can convert it to a dbg.value
/// intrinsic if the alloca gets promoted. /// intrinsic if the alloca gets promoted.
SmallVector<TinyPtrVector<DbgInfoIntrinsic *>, 8> AllocaDbgDeclares; SmallVector<DbgDeclareInst *, 8> AllocaDbgDeclares;
/// The set of basic blocks the renamer has already visited. /// 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 // Record debuginfo for the store and remove the declaration's
// debuginfo. // debuginfo.
for (DbgInfoIntrinsic *DII : Info.DbgDeclares) { if (DbgDeclareInst *DDI = Info.DbgDeclare) {
DIBuilder DIB(*AI->getModule(), /*AllowUnresolved*/ false); DIBuilder DIB(*AI->getModule(), /*AllowUnresolved*/ false);
ConvertDebugDeclareToDebugValue(DII, Info.OnlyStore, DIB); ConvertDebugDeclareToDebugValue(DDI, Info.OnlyStore, DIB);
DII->eraseFromParent(); DDI->eraseFromParent();
LBI.deleteValue(DII); LBI.deleteValue(DDI);
} }
// Remove the (now dead) store and alloca. // Remove the (now dead) store and alloca.
Info.OnlyStore->eraseFromParent(); Info.OnlyStore->eraseFromParent();
@ -505,9 +505,9 @@ static bool promoteSingleBlockAlloca(AllocaInst *AI, const AllocaInfo &Info,
while (!AI->use_empty()) { while (!AI->use_empty()) {
StoreInst *SI = cast<StoreInst>(AI->user_back()); StoreInst *SI = cast<StoreInst>(AI->user_back());
// Record debuginfo for the store before removing it. // Record debuginfo for the store before removing it.
for (DbgInfoIntrinsic *DII : Info.DbgDeclares) { if (DbgDeclareInst *DDI = Info.DbgDeclare) {
DIBuilder DIB(*AI->getModule(), /*AllowUnresolved*/ false); DIBuilder DIB(*AI->getModule(), /*AllowUnresolved*/ false);
ConvertDebugDeclareToDebugValue(DII, SI, DIB); ConvertDebugDeclareToDebugValue(DDI, SI, DIB);
} }
SI->eraseFromParent(); SI->eraseFromParent();
LBI.deleteValue(SI); LBI.deleteValue(SI);
@ -517,9 +517,9 @@ static bool promoteSingleBlockAlloca(AllocaInst *AI, const AllocaInfo &Info,
LBI.deleteValue(AI); LBI.deleteValue(AI);
// The alloca's debuginfo can be removed as well. // The alloca's debuginfo can be removed as well.
for (DbgInfoIntrinsic *DII : Info.DbgDeclares) { if (DbgDeclareInst *DDI = Info.DbgDeclare) {
DII->eraseFromParent(); DDI->eraseFromParent();
LBI.deleteValue(DII); LBI.deleteValue(DDI);
} }
++NumLocalPromoted; ++NumLocalPromoted;
@ -587,8 +587,8 @@ void PromoteMem2Reg::run() {
} }
// Remember the dbg.declare intrinsic describing this alloca, if any. // Remember the dbg.declare intrinsic describing this alloca, if any.
if (!Info.DbgDeclares.empty()) if (Info.DbgDeclare)
AllocaDbgDeclares[AllocaNum] = Info.DbgDeclares; AllocaDbgDeclares[AllocaNum] = Info.DbgDeclare;
// Keep the reverse mapping of the 'Allocas' array for the rename pass. // Keep the reverse mapping of the 'Allocas' array for the rename pass.
AllocaLookup[Allocas[AllocaNum]] = AllocaNum; AllocaLookup[Allocas[AllocaNum]] = AllocaNum;
@ -666,9 +666,9 @@ void PromoteMem2Reg::run() {
} }
// Remove alloca's dbg.declare instrinsics from the function. // Remove alloca's dbg.declare instrinsics from the function.
for (auto &Declares : AllocaDbgDeclares) for (DbgDeclareInst *DDI : AllocaDbgDeclares)
for (auto *DII : Declares) if (DDI)
DII->eraseFromParent(); DDI->eraseFromParent();
// Loop over all of the PHI nodes and see if there are any that we can get // 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 // 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. // The currently active variable for this block is now the PHI.
IncomingVals[AllocaNo] = APN; IncomingVals[AllocaNo] = APN;
for (DbgInfoIntrinsic *DII : AllocaDbgDeclares[AllocaNo]) if (DbgDeclareInst *DDI = AllocaDbgDeclares[AllocaNo])
ConvertDebugDeclareToDebugValue(DII, APN, DIB); ConvertDebugDeclareToDebugValue(DDI, APN, DIB);
// Get the next phi node. // Get the next phi node.
++PNI; ++PNI;
@ -952,8 +952,8 @@ NextIteration:
// what value were we writing? // what value were we writing?
IncomingVals[ai->second] = SI->getOperand(0); IncomingVals[ai->second] = SI->getOperand(0);
// Record debuginfo for the store before removing it. // Record debuginfo for the store before removing it.
for (DbgInfoIntrinsic *DII : AllocaDbgDeclares[ai->second]) if (DbgDeclareInst *DDI = AllocaDbgDeclares[ai->second])
ConvertDebugDeclareToDebugValue(DII, SI, DIB); ConvertDebugDeclareToDebugValue(DDI, SI, DIB);
BB->getInstList().erase(SI); BB->getInstList().erase(SI);
} }
} }

View File

@ -1,100 +0,0 @@
; 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)

View File

@ -1,67 +0,0 @@
; 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)

View File

@ -20,10 +20,10 @@ target triple = "x86_64-unknown-linux-gnu"
; ;
; There should be no debug info for the padding. ; There should be no debug info for the padding.
; CHECK-NOT: DW_OP_LLVM_fragment, 56 ; 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: DIExpression(DW_OP_LLVM_fragment, 32, 24)
; CHECK-NOT: DW_OP_LLVM_fragment, 56 ; CHECK-NOT: DW_OP_LLVM_fragment, 56
; CHECK: DIExpression(DW_OP_LLVM_fragment, 0, 32)
; CHECK-NOT: DW_OP_LLVM_fragment, 56
%struct.prog_src_register = type { i32, i24 } %struct.prog_src_register = type { i32, i24 }
; Function Attrs: nounwind ; Function Attrs: nounwind

View File

@ -1,59 +0,0 @@
; 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]*

View File

@ -1,94 +0,0 @@
; 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)

View File

@ -1,91 +0,0 @@
; 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)

View File

@ -1,127 +0,0 @@
; 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)