[codeview] Describe local variables in registers

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@260746 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Reid Kleckner 2016-02-12 21:48:30 +00:00
parent 2ee5bb8ea1
commit 43c4ddff1c
3 changed files with 515 additions and 50 deletions

View File

@ -105,18 +105,32 @@ unsigned CodeViewDebug::maybeRecordFile(const DIFile *F) {
return Insertion.first->second; return Insertion.first->second;
} }
CodeViewDebug::InlineSite &CodeViewDebug::getInlineSite(const DILocation *Loc) { CodeViewDebug::InlineSite &
const DILocation *InlinedAt = Loc->getInlinedAt(); CodeViewDebug::getInlineSite(const DILocation *InlinedAt,
const DISubprogram *Inlinee) {
auto Insertion = CurFn->InlineSites.insert({InlinedAt, InlineSite()}); auto Insertion = CurFn->InlineSites.insert({InlinedAt, InlineSite()});
InlineSite *Site = &Insertion.first->second; InlineSite *Site = &Insertion.first->second;
if (Insertion.second) { if (Insertion.second) {
Site->SiteFuncId = NextFuncId++; Site->SiteFuncId = NextFuncId++;
Site->Inlinee = Loc->getScope()->getSubprogram(); Site->Inlinee = Inlinee;
InlinedSubprograms.insert(Loc->getScope()->getSubprogram()); InlinedSubprograms.insert(Inlinee);
} }
return *Site; return *Site;
} }
void CodeViewDebug::recordLocalVariable(LocalVariable &&Var,
const DILocation *InlinedAt) {
if (InlinedAt) {
// This variable was inlined. Associate it with the InlineSite.
const DISubprogram *Inlinee = Var.DIVar->getScope()->getSubprogram();
InlineSite &Site = getInlineSite(InlinedAt, Inlinee);
Site.InlinedLocals.emplace_back(Var);
} else {
// This variable goes in the main ProcSym.
CurFn->Locals.emplace_back(Var);
}
}
static void addLocIfNotPresent(SmallVectorImpl<const DILocation *> &Locs, static void addLocIfNotPresent(SmallVectorImpl<const DILocation *> &Locs,
const DILocation *Loc) { const DILocation *Loc) {
auto B = Locs.begin(), E = Locs.end(); auto B = Locs.begin(), E = Locs.end();
@ -154,18 +168,19 @@ void CodeViewDebug::maybeRecordLocation(DebugLoc DL,
CurFn->LastLoc = DL; CurFn->LastLoc = DL;
unsigned FuncId = CurFn->FuncId; unsigned FuncId = CurFn->FuncId;
if (DL->getInlinedAt()) { if (const DILocation *SiteLoc = DL->getInlinedAt()) {
const DILocation *Loc = DL.get(); const DILocation *Loc = DL.get();
// If this location was actually inlined from somewhere else, give it the ID // If this location was actually inlined from somewhere else, give it the ID
// of the inline call site. // of the inline call site.
FuncId = getInlineSite(Loc).SiteFuncId; FuncId =
getInlineSite(SiteLoc, Loc->getScope()->getSubprogram()).SiteFuncId;
// Ensure we have links in the tree of inline call sites. // Ensure we have links in the tree of inline call sites.
const DILocation *SiteLoc;
bool FirstLoc = true; bool FirstLoc = true;
while ((SiteLoc = Loc->getInlinedAt())) { while ((SiteLoc = Loc->getInlinedAt())) {
InlineSite &Site = getInlineSite(Loc); InlineSite &Site =
getInlineSite(SiteLoc, Loc->getScope()->getSubprogram());
if (!FirstLoc) if (!FirstLoc)
addLocIfNotPresent(Site.ChildSites, Loc); addLocIfNotPresent(Site.ChildSites, Loc);
FirstLoc = false; FirstLoc = false;
@ -477,45 +492,148 @@ void CodeViewDebug::emitDebugInfoForFunction(const Function *GV,
OS.EmitCVLinetableDirective(FI.FuncId, Fn, FI.End); OS.EmitCVLinetableDirective(FI.FuncId, Fn, FI.End);
} }
void CodeViewDebug::collectVariableInfoFromMMITable() { CodeViewDebug::LocalVarDefRange
for (const auto &VI : MMI->getVariableDbgInfo()) { CodeViewDebug::createDefRangeMem(uint16_t CVRegister, int Offset) {
LocalVarDefRange DR;
DR.InMemory = 1;
DR.DataOffset = Offset;
assert(DR.DataOffset == Offset && "truncation");
DR.StructOffset = 0;
DR.CVRegister = CVRegister;
return DR;
}
CodeViewDebug::LocalVarDefRange
CodeViewDebug::createDefRangeReg(uint16_t CVRegister) {
LocalVarDefRange DR;
DR.InMemory = 0;
DR.DataOffset = 0;
DR.StructOffset = 0;
DR.CVRegister = CVRegister;
return DR;
}
void CodeViewDebug::collectVariableInfoFromMMITable(
DenseSet<InlinedVariable> &Processed) {
const TargetSubtargetInfo &TSI = Asm->MF->getSubtarget();
const TargetFrameLowering *TFI = TSI.getFrameLowering();
const TargetRegisterInfo *TRI = TSI.getRegisterInfo();
for (const MachineModuleInfo::VariableDbgInfo &VI :
MMI->getVariableDbgInfo()) {
if (!VI.Var) if (!VI.Var)
continue; continue;
assert(VI.Var->isValidLocationForIntrinsic(VI.Loc) && assert(VI.Var->isValidLocationForIntrinsic(VI.Loc) &&
"Expected inlined-at fields to agree"); "Expected inlined-at fields to agree");
Processed.insert(InlinedVariable(VI.Var, VI.Loc->getInlinedAt()));
LexicalScope *Scope = LScopes.findLexicalScope(VI.Loc); LexicalScope *Scope = LScopes.findLexicalScope(VI.Loc);
// If variable scope is not found then skip this variable. // If variable scope is not found then skip this variable.
if (!Scope) if (!Scope)
continue; continue;
LocalVariable Var;
Var.DIVar = VI.Var;
// Get the frame register used and the offset. // Get the frame register used and the offset.
unsigned FrameReg = 0; unsigned FrameReg = 0;
const TargetSubtargetInfo &TSI = Asm->MF->getSubtarget(); int FrameOffset = TFI->getFrameIndexReference(*Asm->MF, VI.Slot, FrameReg);
const TargetFrameLowering *TFI = TSI.getFrameLowering(); uint16_t CVReg = TRI->getCodeViewRegNum(FrameReg);
const TargetRegisterInfo *TRI = TSI.getRegisterInfo();
Var.RegisterOffset = TFI->getFrameIndexReference(*Asm->MF, VI.Slot, FrameReg);
Var.CVRegister = TRI->getCodeViewRegNum(FrameReg);
// Calculate the label ranges. // Calculate the label ranges.
LocalVarDefRange DefRange = createDefRangeMem(CVReg, FrameOffset);
for (const InsnRange &Range : Scope->getRanges()) { for (const InsnRange &Range : Scope->getRanges()) {
const MCSymbol *Begin = getLabelBeforeInsn(Range.first); const MCSymbol *Begin = getLabelBeforeInsn(Range.first);
const MCSymbol *End = getLabelAfterInsn(Range.second); const MCSymbol *End = getLabelAfterInsn(Range.second);
Var.Ranges.push_back({Begin, End}); End = End ? End : Asm->getFunctionEnd();
DefRange.Ranges.emplace_back(Begin, End);
} }
if (VI.Loc->getInlinedAt()) { LocalVariable Var;
// This variable was inlined. Associate it with the InlineSite. Var.DIVar = VI.Var;
InlineSite &Site = getInlineSite(VI.Loc); Var.DefRanges.emplace_back(std::move(DefRange));
Site.InlinedLocals.emplace_back(std::move(Var)); recordLocalVariable(std::move(Var), VI.Loc->getInlinedAt());
} else { }
// This variable goes in the main ProcSym. }
CurFn->Locals.emplace_back(std::move(Var));
void CodeViewDebug::collectVariableInfo(const DISubprogram *SP) {
DenseSet<InlinedVariable> Processed;
// Grab the variable info that was squirreled away in the MMI side-table.
collectVariableInfoFromMMITable(Processed);
const TargetRegisterInfo *TRI = Asm->MF->getSubtarget().getRegisterInfo();
for (const auto &I : DbgValues) {
InlinedVariable IV = I.first;
if (Processed.count(IV))
continue;
const DILocalVariable *DIVar = IV.first;
const DILocation *InlinedAt = IV.second;
// Instruction ranges, specifying where IV is accessible.
const auto &Ranges = I.second;
LexicalScope *Scope = nullptr;
if (InlinedAt)
Scope = LScopes.findInlinedScope(DIVar->getScope(), InlinedAt);
else
Scope = LScopes.findLexicalScope(DIVar->getScope());
// If variable scope is not found then skip this variable.
if (!Scope)
continue;
LocalVariable Var;
Var.DIVar = DIVar;
// Calculate the definition ranges.
for (auto I = Ranges.begin(), E = Ranges.end(); I != E; ++I) {
const InsnRange &Range = *I;
const MachineInstr *DVInst = Range.first;
assert(DVInst->isDebugValue() && "Invalid History entry");
const DIExpression *DIExpr = DVInst->getDebugExpression();
// Bail if there is a complex DWARF expression for now.
if (DIExpr && DIExpr->getNumElements() > 0)
continue;
// Handle the two cases we can handle: indirect in memory and in register.
bool IsIndirect = DVInst->getOperand(1).isImm();
unsigned CVReg = TRI->getCodeViewRegNum(DVInst->getOperand(0).getReg());
{
LocalVarDefRange DefRange;
if (IsIndirect) {
int64_t Offset = DVInst->getOperand(1).getImm();
DefRange = createDefRangeMem(CVReg, Offset);
} else {
DefRange = createDefRangeReg(CVReg);
}
if (Var.DefRanges.empty() ||
Var.DefRanges.back().isDifferentLocation(DefRange)) {
Var.DefRanges.emplace_back(std::move(DefRange));
}
}
// Compute the label range.
const MCSymbol *Begin = getLabelBeforeInsn(Range.first);
const MCSymbol *End = getLabelAfterInsn(Range.second);
if (!End) {
if (std::next(I) != E)
End = getLabelBeforeInsn(std::next(I)->first);
else
End = Asm->getFunctionEnd();
}
// If the last range end is our begin, just extend the last range.
// Otherwise make a new range.
SmallVectorImpl<std::pair<const MCSymbol *, const MCSymbol *>> &Ranges =
Var.DefRanges.back().Ranges;
if (!Ranges.empty() && Ranges.back().second == Begin)
Ranges.back().second = End;
else
Ranges.emplace_back(Begin, End);
// FIXME: Do more range combining.
} }
recordLocalVariable(std::move(Var), InlinedAt);
} }
} }
@ -572,6 +690,8 @@ void CodeViewDebug::emitLocalVariable(const LocalVariable &Var) {
uint16_t Flags = 0; uint16_t Flags = 0;
if (Var.DIVar->isParameter()) if (Var.DIVar->isParameter())
Flags |= LocalSym::IsParameter; Flags |= LocalSym::IsParameter;
if (Var.DefRanges.empty())
Flags |= LocalSym::IsOptimizedOut;
OS.AddComment("TypeIndex"); OS.AddComment("TypeIndex");
OS.EmitIntValue(TypeIndex::Int32().getIndex(), 4); OS.EmitIntValue(TypeIndex::Int32().getIndex(), 4);
@ -580,28 +700,42 @@ void CodeViewDebug::emitLocalVariable(const LocalVariable &Var) {
emitNullTerminatedString(OS, Var.DIVar->getName()); emitNullTerminatedString(OS, Var.DIVar->getName());
OS.EmitLabel(LocalEnd); OS.EmitLabel(LocalEnd);
// DefRangeRegisterRelSym record, see SymbolRecord.h for more info. Omit the // Calculate the on disk prefix of the appropriate def range record. The
// LocalVariableAddrRange field from the record. The directive will emit that. // records and on disk formats are described in SymbolRecords.h. BytePrefix
DefRangeRegisterRelSym Sym{}; // should be big enough to hold all forms without memory allocation.
ulittle16_t SymKind = ulittle16_t(S_DEFRANGE_REGISTER_REL); SmallString<20> BytePrefix;
Sym.BaseRegister = Var.CVRegister; for (const LocalVarDefRange &DefRange : Var.DefRanges) {
Sym.Flags = 0; // Unclear what matters here. BytePrefix.clear();
Sym.BasePointerOffset = Var.RegisterOffset; // FIXME: Handle bitpieces.
SmallString<sizeof(Sym) + sizeof(SymKind) - sizeof(LocalVariableAddrRange)> if (DefRange.StructOffset != 0)
BytePrefix; continue;
BytePrefix += StringRef(reinterpret_cast<const char *>(&SymKind),
sizeof(SymKind));
BytePrefix += StringRef(reinterpret_cast<const char *>(&Sym),
sizeof(Sym) - sizeof(LocalVariableAddrRange));
OS.EmitCVDefRangeDirective(Var.Ranges, BytePrefix); if (DefRange.InMemory) {
DefRangeRegisterRelSym Sym{};
ulittle16_t SymKind = ulittle16_t(S_DEFRANGE_REGISTER_REL);
Sym.BaseRegister = DefRange.CVRegister;
Sym.Flags = 0; // Unclear what matters here.
Sym.BasePointerOffset = DefRange.DataOffset;
BytePrefix +=
StringRef(reinterpret_cast<const char *>(&SymKind), sizeof(SymKind));
BytePrefix += StringRef(reinterpret_cast<const char *>(&Sym),
sizeof(Sym) - sizeof(LocalVariableAddrRange));
} else {
assert(DefRange.DataOffset == 0 && "unexpected offset into register");
DefRangeRegisterSym Sym{};
ulittle16_t SymKind = ulittle16_t(S_DEFRANGE_REGISTER);
Sym.Register = DefRange.CVRegister;
Sym.MayHaveNoName = 0; // Unclear what matters here.
BytePrefix +=
StringRef(reinterpret_cast<const char *>(&SymKind), sizeof(SymKind));
BytePrefix += StringRef(reinterpret_cast<const char *>(&Sym),
sizeof(Sym) - sizeof(LocalVariableAddrRange));
}
OS.EmitCVDefRangeDirective(DefRange.Ranges, BytePrefix);
}
} }
void CodeViewDebug::endFunction(const MachineFunction *MF) { void CodeViewDebug::endFunction(const MachineFunction *MF) {
collectVariableInfoFromMMITable();
DebugHandlerBase::endFunction(MF);
if (!Asm || !CurFn) // We haven't created any debug info for this function. if (!Asm || !CurFn) // We haven't created any debug info for this function.
return; return;
@ -609,6 +743,10 @@ void CodeViewDebug::endFunction(const MachineFunction *MF) {
assert(FnDebugInfo.count(GV)); assert(FnDebugInfo.count(GV));
assert(CurFn == &FnDebugInfo[GV]); assert(CurFn == &FnDebugInfo[GV]);
collectVariableInfo(getDISubprogram(GV));
DebugHandlerBase::endFunction(MF);
// Don't emit anything if we don't have any line tables. // Don't emit anything if we don't have any line tables.
if (!CurFn->HaveLineInfo) { if (!CurFn->HaveLineInfo) {
FnDebugInfo.erase(GV); FnDebugInfo.erase(GV);

View File

@ -35,13 +35,40 @@ class LexicalScope;
class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase { class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase {
MCStreamer &OS; MCStreamer &OS;
/// Represents the most general definition range.
struct LocalVarDefRange {
/// Indicates that variable data is stored in memory relative to the
/// specified register.
int InMemory : 1;
/// Offset of variable data in memory.
int DataOffset : 31;
/// Offset of the data into the user level struct. If zero, no splitting
/// occurred.
uint16_t StructOffset;
/// Register containing the data or the register base of the memory
/// location containing the data.
uint16_t CVRegister;
/// Compares all location fields. This includes all fields except the label
/// ranges.
bool isDifferentLocation(LocalVarDefRange &O) {
return InMemory != O.InMemory || DataOffset != O.DataOffset ||
StructOffset != O.StructOffset || CVRegister != O.CVRegister;
}
SmallVector<std::pair<const MCSymbol *, const MCSymbol *>, 1> Ranges;
};
static LocalVarDefRange createDefRangeMem(uint16_t CVRegister, int Offset);
static LocalVarDefRange createDefRangeReg(uint16_t CVRegister);
/// Similar to DbgVariable in DwarfDebug, but not dwarf-specific. /// Similar to DbgVariable in DwarfDebug, but not dwarf-specific.
struct LocalVariable { struct LocalVariable {
const DILocalVariable *DIVar = nullptr; const DILocalVariable *DIVar = nullptr;
SmallVector<std::pair<const MCSymbol *, const MCSymbol *>, 1> Ranges; SmallVector<LocalVarDefRange, 1> DefRanges;
unsigned CVRegister = 0;
int RegisterOffset = 0;
// FIXME: Add support for DIExpressions.
}; };
struct InlineSite { struct InlineSite {
@ -74,7 +101,8 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase {
unsigned NextFuncId = 0; unsigned NextFuncId = 0;
InlineSite &getInlineSite(const DILocation *Loc); InlineSite &getInlineSite(const DILocation *InlinedAt,
const DISubprogram *Inlinee);
static void collectInlineSiteChildren(SmallVectorImpl<unsigned> &Children, static void collectInlineSiteChildren(SmallVectorImpl<unsigned> &Children,
const FunctionInfo &FI, const FunctionInfo &FI,
@ -123,7 +151,15 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase {
void emitInlinedCallSite(const FunctionInfo &FI, const DILocation *InlinedAt, void emitInlinedCallSite(const FunctionInfo &FI, const DILocation *InlinedAt,
const InlineSite &Site); const InlineSite &Site);
void collectVariableInfoFromMMITable(); typedef DbgValueHistoryMap::InlinedVariable InlinedVariable;
void collectVariableInfo(const DISubprogram *SP);
void collectVariableInfoFromMMITable(DenseSet<InlinedVariable> &Processed);
/// Records information about a local variable in the appropriate scope. In
/// particular, locals from inlined code live inside the inlining site.
void recordLocalVariable(LocalVariable &&Var, const DILocation *Loc);
void emitLocalVariable(const LocalVariable &Var); void emitLocalVariable(const LocalVariable &Var);

View File

@ -0,0 +1,291 @@
; RUN: llc < %s | FileCheck %s --check-prefix=ASM
; RUN: llc < %s -filetype=obj | llvm-readobj -codeview - | FileCheck %s --check-prefix=OBJ
; Generated from:
; volatile int x;
; int getint(void);
; void putint(int);
; static inline int inlineinc(int a) {
; int b = a + 1;
; ++x;
; return b;
; }
; void f(int p) {
; if (p) {
; int a = getint();
; int b = inlineinc(a);
; putint(b);
; } else {
; int c = getint();
; putint(c);
; }
; }
; ASM: f: # @f
; ASM: .Lfunc_begin0:
; ASM: # BB#0: # %entry
; ASM: pushq %rsi
; ASM: subq $32, %rsp
; ASM: #DEBUG_VALUE: f:p <- %ECX
; ASM: movl %ecx, %esi
; ASM: [[p_ecx_esi:\.Ltmp.*]]:
; ASM: #DEBUG_VALUE: f:p <- %ESI
; ASM: callq getint
; ASM: [[after_getint:\.Ltmp.*]]:
; ASM: #DEBUG_VALUE: a <- %EAX
; ASM: #DEBUG_VALUE: inlineinc:a <- %EAX
; ASM: #DEBUG_VALUE: c <- %EAX
; ASM: testl %esi, %esi
; ASM: je .LBB0_2
; ASM: # BB#1: # %if.then
; ASM: #DEBUG_VALUE: c <- %EAX
; ASM: #DEBUG_VALUE: inlineinc:a <- %EAX
; ASM: #DEBUG_VALUE: a <- %EAX
; ASM: #DEBUG_VALUE: f:p <- %ESI
; ASM: incl %eax
; ASM: [[after_inc_eax:\.Ltmp.*]]:
; ASM: #DEBUG_VALUE: inlineinc:b <- %EAX
; ASM: #DEBUG_VALUE: b <- %EAX
; ASM: incl x(%rip)
; ASM: [[after_if:\.Ltmp.*]]:
; ASM: .LBB0_2: # %if.else
; ASM: #DEBUG_VALUE: f:p <- %ESI
; ASM: movl %eax, %ecx
; ASM: addq $32, %rsp
; ASM: popq %rsi
; ASM: [[func_end:\.Ltmp.*]]:
; ASM: rex64 jmp putint # TAILCALL
; ASM: .short 4414 # Record kind: S_LOCAL
; ASM: .asciz "p"
; ASM: .cv_def_range .Lfunc_begin0 [[p_ecx_esi]], "A\021\022\000\000\000"
; ASM: .cv_def_range [[p_ecx_esi]] [[func_end]], "A\021\027\000\000\000"
; ASM: .short 4414 # Record kind: S_LOCAL
; ASM: .asciz "a"
; ASM: .cv_def_range [[after_getint]] [[after_inc_eax]], "A\021\021\000\000\000"
; ASM: .short 4414 # Record kind: S_LOCAL
; ASM: .asciz "c"
; ASM: .cv_def_range [[after_getint]] [[after_inc_eax]], "A\021\021\000\000\000"
; ASM: .short 4414 # Record kind: S_LOCAL
; ASM: .asciz "b"
; ASM: .cv_def_range [[after_inc_eax]] [[after_if]], "A\021\021\000\000\000"
; ASM: .short 4429 # Record kind: S_INLINESITE
; ASM: .short 4414 # Record kind: S_LOCAL
; ASM: .asciz "a"
; ASM: .cv_def_range [[after_getint]] [[after_inc_eax]], "A\021\021\000\000\000"
; ASM: .short 4414 # Record kind: S_LOCAL
; ASM: .asciz "b"
; ASM: .cv_def_range [[after_inc_eax]] [[after_if]], "A\021\021\000\000\000"
; ASM: .short 4430 # Record kind: S_INLINESITE_END
; OBJ: Subsection [
; OBJ: SubSectionType: Symbols (0xF1)
; OBJ: ProcStart {
; OBJ: DisplayName: f
; OBJ: }
; OBJ: Local {
; OBJ: Type: int (0x74)
; OBJ: Flags [ (0x1)
; OBJ: IsParameter (0x1)
; OBJ: ]
; OBJ: VarName: p
; OBJ: }
; OBJ: DefRangeRegister {
; OBJ: Register: 18
; OBJ: LocalVariableAddrRange {
; OBJ: OffsetStart: .text+0x0
; OBJ: ISectStart: 0x0
; OBJ: Range: 0x7
; OBJ: }
; OBJ: }
; OBJ: DefRangeRegister {
; OBJ: Register: 23
; OBJ: LocalVariableAddrRange {
; OBJ: OffsetStart: .text+0x7
; OBJ: ISectStart: 0x0
; OBJ: Range: 0x18
; OBJ: }
; OBJ: }
; OBJ: Local {
; OBJ: Type: int (0x74)
; OBJ: Flags [ (0x0)
; OBJ: ]
; OBJ: VarName: a
; OBJ: }
; OBJ: DefRangeRegister {
; OBJ: Register: 17
; OBJ: LocalVariableAddrRange {
; OBJ: OffsetStart: .text+0xC
; OBJ: ISectStart: 0x0
; OBJ: Range: 0x6
; OBJ: }
; OBJ: }
; OBJ: Local {
; OBJ: Type: int (0x74)
; OBJ: Flags [ (0x0)
; OBJ: ]
; OBJ: VarName: c
; OBJ: }
; OBJ: DefRangeRegister {
; OBJ: Register: 17
; OBJ: LocalVariableAddrRange {
; OBJ: OffsetStart: .text+0xC
; OBJ: ISectStart: 0x0
; OBJ: Range: 0x6
; OBJ: }
; OBJ: }
; OBJ: Local {
; OBJ: Type: int (0x74)
; OBJ: Flags [ (0x0)
; OBJ: ]
; OBJ: VarName: b
; OBJ: }
; OBJ: DefRangeRegister {
; OBJ: Register: 17
; OBJ: LocalVariableAddrRange {
; OBJ: OffsetStart: .text+0x12
; OBJ: ISectStart: 0x0
; OBJ: Range: 0x6
; OBJ: }
; OBJ: }
; OBJ: InlineSite {
; OBJ: PtrParent: 0x0
; OBJ: PtrEnd: 0x0
; OBJ: Inlinee: inlineinc (0x1003)
; OBJ: }
; OBJ: Local {
; OBJ: Type: int (0x74)
; OBJ: Flags [ (0x1)
; OBJ: IsParameter (0x1)
; OBJ: ]
; OBJ: VarName: a
; OBJ: }
; OBJ: DefRangeRegister {
; OBJ: Register: 17
; OBJ: LocalVariableAddrRange {
; OBJ: OffsetStart: .text+0xC
; OBJ: ISectStart: 0x0
; OBJ: Range: 0x6
; OBJ: }
; OBJ: }
; OBJ: Local {
; OBJ: Type: int (0x74)
; OBJ: Flags [ (0x0)
; OBJ: ]
; OBJ: VarName: b
; OBJ: }
; OBJ: DefRangeRegister {
; OBJ: Register: 17
; OBJ: LocalVariableAddrRange {
; OBJ: OffsetStart: .text+0x12
; OBJ: ISectStart: 0x0
; OBJ: Range: 0x6
; OBJ: }
; OBJ: }
; OBJ: InlineSiteEnd {
; OBJ: }
; OBJ: ProcEnd
; OBJ: ]
; ModuleID = 't.cpp'
target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-windows-msvc18.0.0"
@x = internal global i32 0, align 4
; Function Attrs: nounwind uwtable
define void @f(i32 %p) #0 !dbg !4 {
entry:
tail call void @llvm.dbg.value(metadata i32 %p, i64 0, metadata !9, metadata !29), !dbg !30
%tobool = icmp eq i32 %p, 0, !dbg !31
%call2 = tail call i32 @getint() #3, !dbg !32
br i1 %tobool, label %if.else, label %if.then, !dbg !33
if.then: ; preds = %entry
tail call void @llvm.dbg.value(metadata i32 %call2, i64 0, metadata !10, metadata !29), !dbg !34
tail call void @llvm.dbg.value(metadata i32 %call2, i64 0, metadata !20, metadata !29), !dbg !35
%add.i = add nsw i32 %call2, 1, !dbg !37
tail call void @llvm.dbg.value(metadata i32 %add.i, i64 0, metadata !21, metadata !29), !dbg !38
%0 = load volatile i32, i32* @x, align 4, !dbg !39, !tbaa !40
%inc.i = add nsw i32 %0, 1, !dbg !39
store volatile i32 %inc.i, i32* @x, align 4, !dbg !39, !tbaa !40
tail call void @llvm.dbg.value(metadata i32 %add.i, i64 0, metadata !13, metadata !29), !dbg !44
tail call void @putint(i32 %add.i) #3, !dbg !45
br label %if.end, !dbg !46
if.else: ; preds = %entry
tail call void @llvm.dbg.value(metadata i32 %call2, i64 0, metadata !14, metadata !29), !dbg !47
tail call void @putint(i32 %call2) #3, !dbg !48
br label %if.end
if.end: ; preds = %if.else, %if.then
ret void, !dbg !49
}
declare i32 @getint() #1
declare void @putint(i32) #1
; Function Attrs: nounwind readnone
declare void @llvm.dbg.value(metadata, i64, metadata, metadata) #2
attributes #0 = { nounwind uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #2 = { nounwind readnone }
attributes #3 = { nounwind }
!llvm.dbg.cu = !{!0}
!llvm.module.flags = !{!25, !26, !27}
!llvm.ident = !{!28}
!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 3.9.0 (trunk 260617) (llvm/trunk 260619)", isOptimized: true, runtimeVersion: 0, emissionKind: 1, enums: !2, subprograms: !3, globals: !22)
!1 = !DIFile(filename: "t.cpp", directory: "D:\5Csrc\5Cllvm\5Cbuild")
!2 = !{}
!3 = !{!4, !16}
!4 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 9, type: !5, isLocal: false, isDefinition: true, scopeLine: 9, flags: DIFlagPrototyped, isOptimized: true, variables: !8)
!5 = !DISubroutineType(types: !6)
!6 = !{null, !7}
!7 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed)
!8 = !{!9, !10, !13, !14}
!9 = !DILocalVariable(name: "p", arg: 1, scope: !4, file: !1, line: 9, type: !7)
!10 = !DILocalVariable(name: "a", scope: !11, file: !1, line: 11, type: !7)
!11 = distinct !DILexicalBlock(scope: !12, file: !1, line: 10, column: 10)
!12 = distinct !DILexicalBlock(scope: !4, file: !1, line: 10, column: 7)
!13 = !DILocalVariable(name: "b", scope: !11, file: !1, line: 12, type: !7)
!14 = !DILocalVariable(name: "c", scope: !15, file: !1, line: 15, type: !7)
!15 = distinct !DILexicalBlock(scope: !12, file: !1, line: 14, column: 10)
!16 = distinct !DISubprogram(name: "inlineinc", scope: !1, file: !1, line: 4, type: !17, isLocal: true, isDefinition: true, scopeLine: 4, flags: DIFlagPrototyped, isOptimized: true, variables: !19)
!17 = !DISubroutineType(types: !18)
!18 = !{!7, !7}
!19 = !{!20, !21}
!20 = !DILocalVariable(name: "a", arg: 1, scope: !16, file: !1, line: 4, type: !7)
!21 = !DILocalVariable(name: "b", scope: !16, file: !1, line: 5, type: !7)
!22 = !{!23}
!23 = !DIGlobalVariable(name: "x", scope: !0, file: !1, line: 1, type: !24, isLocal: false, isDefinition: true, variable: i32* @x)
!24 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !7)
!25 = !{i32 2, !"CodeView", i32 1}
!26 = !{i32 2, !"Debug Info Version", i32 3}
!27 = !{i32 1, !"PIC Level", i32 2}
!28 = !{!"clang version 3.9.0 (trunk 260617) (llvm/trunk 260619)"}
!29 = !DIExpression()
!30 = !DILocation(line: 9, column: 12, scope: !4)
!31 = !DILocation(line: 10, column: 7, scope: !12)
!32 = !DILocation(line: 15, column: 13, scope: !15)
!33 = !DILocation(line: 10, column: 7, scope: !4)
!34 = !DILocation(line: 11, column: 9, scope: !11)
!35 = !DILocation(line: 4, column: 33, scope: !16, inlinedAt: !36)
!36 = distinct !DILocation(line: 12, column: 13, scope: !11)
!37 = !DILocation(line: 5, column: 13, scope: !16, inlinedAt: !36)
!38 = !DILocation(line: 5, column: 7, scope: !16, inlinedAt: !36)
!39 = !DILocation(line: 6, column: 3, scope: !16, inlinedAt: !36)
!40 = !{!41, !41, i64 0}
!41 = !{!"int", !42, i64 0}
!42 = !{!"omnipotent char", !43, i64 0}
!43 = !{!"Simple C/C++ TBAA"}
!44 = !DILocation(line: 12, column: 9, scope: !11)
!45 = !DILocation(line: 13, column: 5, scope: !11)
!46 = !DILocation(line: 14, column: 3, scope: !11)
!47 = !DILocation(line: 15, column: 9, scope: !15)
!48 = !DILocation(line: 16, column: 5, scope: !15)
!49 = !DILocation(line: 18, column: 1, scope: !4)