diff options
Diffstat (limited to 'llvm')
| -rw-r--r-- | llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp | 228 | ||||
| -rw-r--r-- | llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h | 48 | ||||
| -rw-r--r-- | llvm/test/DebugInfo/COFF/register-variables.ll | 291 |
3 files changed, 516 insertions, 51 deletions
diff --git a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp index 481772944b4..9218579826f 100644 --- a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp @@ -105,18 +105,32 @@ unsigned CodeViewDebug::maybeRecordFile(const DIFile *F) { return Insertion.first->second; } -CodeViewDebug::InlineSite &CodeViewDebug::getInlineSite(const DILocation *Loc) { - const DILocation *InlinedAt = Loc->getInlinedAt(); +CodeViewDebug::InlineSite & +CodeViewDebug::getInlineSite(const DILocation *InlinedAt, + const DISubprogram *Inlinee) { auto Insertion = CurFn->InlineSites.insert({InlinedAt, InlineSite()}); InlineSite *Site = &Insertion.first->second; if (Insertion.second) { Site->SiteFuncId = NextFuncId++; - Site->Inlinee = Loc->getScope()->getSubprogram(); - InlinedSubprograms.insert(Loc->getScope()->getSubprogram()); + Site->Inlinee = Inlinee; + InlinedSubprograms.insert(Inlinee); } 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, const DILocation *Loc) { auto B = Locs.begin(), E = Locs.end(); @@ -154,18 +168,19 @@ void CodeViewDebug::maybeRecordLocation(DebugLoc DL, CurFn->LastLoc = DL; unsigned FuncId = CurFn->FuncId; - if (DL->getInlinedAt()) { + if (const DILocation *SiteLoc = DL->getInlinedAt()) { const DILocation *Loc = DL.get(); // If this location was actually inlined from somewhere else, give it the ID // 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. - const DILocation *SiteLoc; bool FirstLoc = true; while ((SiteLoc = Loc->getInlinedAt())) { - InlineSite &Site = getInlineSite(Loc); + InlineSite &Site = + getInlineSite(SiteLoc, Loc->getScope()->getSubprogram()); if (!FirstLoc) addLocIfNotPresent(Site.ChildSites, Loc); FirstLoc = false; @@ -477,45 +492,148 @@ void CodeViewDebug::emitDebugInfoForFunction(const Function *GV, OS.EmitCVLinetableDirective(FI.FuncId, Fn, FI.End); } -void CodeViewDebug::collectVariableInfoFromMMITable() { - for (const auto &VI : MMI->getVariableDbgInfo()) { +CodeViewDebug::LocalVarDefRange +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) continue; assert(VI.Var->isValidLocationForIntrinsic(VI.Loc) && "Expected inlined-at fields to agree"); + Processed.insert(InlinedVariable(VI.Var, VI.Loc->getInlinedAt())); LexicalScope *Scope = LScopes.findLexicalScope(VI.Loc); // If variable scope is not found then skip this variable. if (!Scope) continue; - LocalVariable Var; - Var.DIVar = VI.Var; - // Get the frame register used and the offset. unsigned FrameReg = 0; - const TargetSubtargetInfo &TSI = Asm->MF->getSubtarget(); - const TargetFrameLowering *TFI = TSI.getFrameLowering(); - const TargetRegisterInfo *TRI = TSI.getRegisterInfo(); - Var.RegisterOffset = TFI->getFrameIndexReference(*Asm->MF, VI.Slot, FrameReg); - Var.CVRegister = TRI->getCodeViewRegNum(FrameReg); + int FrameOffset = TFI->getFrameIndexReference(*Asm->MF, VI.Slot, FrameReg); + uint16_t CVReg = TRI->getCodeViewRegNum(FrameReg); // Calculate the label ranges. + LocalVarDefRange DefRange = createDefRangeMem(CVReg, FrameOffset); for (const InsnRange &Range : Scope->getRanges()) { const MCSymbol *Begin = getLabelBeforeInsn(Range.first); 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()) { - // This variable was inlined. Associate it with the InlineSite. - InlineSite &Site = getInlineSite(VI.Loc); - Site.InlinedLocals.emplace_back(std::move(Var)); - } else { - // This variable goes in the main ProcSym. - CurFn->Locals.emplace_back(std::move(Var)); + LocalVariable Var; + Var.DIVar = VI.Var; + Var.DefRanges.emplace_back(std::move(DefRange)); + recordLocalVariable(std::move(Var), VI.Loc->getInlinedAt()); + } +} + +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; if (Var.DIVar->isParameter()) Flags |= LocalSym::IsParameter; + if (Var.DefRanges.empty()) + Flags |= LocalSym::IsOptimizedOut; OS.AddComment("TypeIndex"); OS.EmitIntValue(TypeIndex::Int32().getIndex(), 4); @@ -580,28 +700,42 @@ void CodeViewDebug::emitLocalVariable(const LocalVariable &Var) { emitNullTerminatedString(OS, Var.DIVar->getName()); OS.EmitLabel(LocalEnd); - // DefRangeRegisterRelSym record, see SymbolRecord.h for more info. Omit the - // LocalVariableAddrRange field from the record. The directive will emit that. - DefRangeRegisterRelSym Sym{}; - ulittle16_t SymKind = ulittle16_t(S_DEFRANGE_REGISTER_REL); - Sym.BaseRegister = Var.CVRegister; - Sym.Flags = 0; // Unclear what matters here. - Sym.BasePointerOffset = Var.RegisterOffset; - SmallString<sizeof(Sym) + sizeof(SymKind) - sizeof(LocalVariableAddrRange)> - BytePrefix; - 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); + // Calculate the on disk prefix of the appropriate def range record. The + // records and on disk formats are described in SymbolRecords.h. BytePrefix + // should be big enough to hold all forms without memory allocation. + SmallString<20> BytePrefix; + for (const LocalVarDefRange &DefRange : Var.DefRanges) { + BytePrefix.clear(); + // FIXME: Handle bitpieces. + if (DefRange.StructOffset != 0) + continue; + + 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) { - collectVariableInfoFromMMITable(); - - DebugHandlerBase::endFunction(MF); - if (!Asm || !CurFn) // We haven't created any debug info for this function. return; @@ -609,6 +743,10 @@ void CodeViewDebug::endFunction(const MachineFunction *MF) { assert(FnDebugInfo.count(GV)); assert(CurFn == &FnDebugInfo[GV]); + collectVariableInfo(getDISubprogram(GV)); + + DebugHandlerBase::endFunction(MF); + // Don't emit anything if we don't have any line tables. if (!CurFn->HaveLineInfo) { FnDebugInfo.erase(GV); diff --git a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h index cec2499fa7f..ce1d8b51c40 100644 --- a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h +++ b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h @@ -35,13 +35,40 @@ class LexicalScope; class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase { 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. struct LocalVariable { const DILocalVariable *DIVar = nullptr; - SmallVector<std::pair<const MCSymbol *, const MCSymbol *>, 1> Ranges; - unsigned CVRegister = 0; - int RegisterOffset = 0; - // FIXME: Add support for DIExpressions. + SmallVector<LocalVarDefRange, 1> DefRanges; }; struct InlineSite { @@ -74,7 +101,8 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase { unsigned NextFuncId = 0; - InlineSite &getInlineSite(const DILocation *Loc); + InlineSite &getInlineSite(const DILocation *InlinedAt, + const DISubprogram *Inlinee); static void collectInlineSiteChildren(SmallVectorImpl<unsigned> &Children, const FunctionInfo &FI, @@ -123,7 +151,15 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase { void emitInlinedCallSite(const FunctionInfo &FI, const DILocation *InlinedAt, 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); diff --git a/llvm/test/DebugInfo/COFF/register-variables.ll b/llvm/test/DebugInfo/COFF/register-variables.ll new file mode 100644 index 00000000000..d970e16300a --- /dev/null +++ b/llvm/test/DebugInfo/COFF/register-variables.ll @@ -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) |

