summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--llvm/include/llvm/MC/MCCodeView.h83
-rw-r--r--llvm/include/llvm/MC/MCFragment.h5
-rw-r--r--llvm/include/llvm/MC/MCObjectStreamer.h11
-rw-r--r--llvm/include/llvm/MC/MCStreamer.h20
-rw-r--r--llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp30
-rw-r--r--llvm/lib/MC/MCAsmStreamer.cpp56
-rw-r--r--llvm/lib/MC/MCCodeView.cpp152
-rw-r--r--llvm/lib/MC/MCObjectStreamer.cpp12
-rw-r--r--llvm/lib/MC/MCParser/AsmParser.cpp169
-rw-r--r--llvm/lib/MC/MCStreamer.cpp46
-rw-r--r--llvm/test/DebugInfo/COFF/inlining-header.ll7
-rw-r--r--llvm/test/DebugInfo/COFF/inlining-levels.ll4
-rw-r--r--llvm/test/DebugInfo/COFF/inlining.ll10
-rw-r--r--llvm/test/DebugInfo/COFF/local-variables.ll3
-rw-r--r--llvm/test/MC/COFF/cv-def-range.s1
-rw-r--r--llvm/test/MC/COFF/cv-empty-linetable.s1
-rw-r--r--llvm/test/MC/COFF/cv-errors.s56
-rw-r--r--llvm/test/MC/COFF/cv-inline-linetable-infloop.s3
-rw-r--r--llvm/test/MC/COFF/cv-inline-linetable-unlikely.s191
-rw-r--r--llvm/test/MC/COFF/cv-inline-linetable-unreachable.s2
-rw-r--r--llvm/test/MC/COFF/cv-inline-linetable.s27
-rw-r--r--llvm/test/MC/COFF/cv-loc-cross-section.s26
-rw-r--r--llvm/test/MC/COFF/cv-loc.s2
23 files changed, 741 insertions, 176 deletions
diff --git a/llvm/include/llvm/MC/MCCodeView.h b/llvm/include/llvm/MC/MCCodeView.h
index 9f881faa492..41521a6549b 100644
--- a/llvm/include/llvm/MC/MCCodeView.h
+++ b/llvm/include/llvm/MC/MCCodeView.h
@@ -105,6 +105,55 @@ public:
static void Make(MCObjectStreamer *MCOS);
};
+/// Information describing a function or inlined call site introduced by
+/// .cv_func_id or .cv_inline_site_id. Accumulates information from .cv_loc
+/// directives used with this function's id or the id of an inlined call site
+/// within this function or inlined call site.
+struct MCCVFunctionInfo {
+ /// If this represents an inlined call site, then ParentFuncIdPlusOne will be
+ /// the parent function id plus one. If this represents a normal function,
+ /// then there is no parent, and ParentFuncIdPlusOne will be FunctionSentinel.
+ /// If this struct is an unallocated slot in the function info vector, then
+ /// ParentFuncIdPlusOne will be zero.
+ unsigned ParentFuncIdPlusOne = 0;
+
+ enum : unsigned { FunctionSentinel = ~0U };
+
+ struct LineInfo {
+ unsigned File;
+ unsigned Line;
+ unsigned Col;
+ };
+
+ LineInfo InlinedAt;
+
+ /// The section of the first .cv_loc directive used for this function, or null
+ /// if none has been seen yet.
+ MCSection *Section = nullptr;
+
+ /// Map from inlined call site id to the inlined at location to use for that
+ /// call site. Call chains are collapsed, so for the call chain 'f -> g -> h',
+ /// the InlinedAtMap of 'f' will contain entries for 'g' and 'h' that both
+ /// list the line info for the 'g' call site.
+ DenseMap<unsigned, LineInfo> InlinedAtMap;
+
+ /// Returns true if this is function info has not yet been used in a
+ /// .cv_func_id or .cv_inline_site_id directive.
+ bool isUnallocatedFunctionInfo() const { return ParentFuncIdPlusOne == 0; }
+
+ /// Returns true if this represents an inlined call site, meaning
+ /// ParentFuncIdPlusOne is neither zero nor ~0U.
+ bool isInlinedCallSite() const {
+ return !isUnallocatedFunctionInfo() &&
+ ParentFuncIdPlusOne != FunctionSentinel;
+ }
+
+ unsigned getParentFuncId() const {
+ assert(isInlinedCallSite());
+ return ParentFuncIdPlusOne - 1;
+ }
+};
+
/// Holds state from .cv_file and .cv_loc directives for later emission.
class CodeViewContext {
public:
@@ -115,6 +164,27 @@ public:
bool addFile(unsigned FileNumber, StringRef Filename);
ArrayRef<StringRef> getFilenames() { return Filenames; }
+ /// Records the function id of a normal function. Returns false if the
+ /// function id has already been used, and true otherwise.
+ bool recordFunctionId(unsigned FuncId);
+
+ /// Records the function id of an inlined call site. Records the "inlined at"
+ /// location info of the call site, including what function or inlined call
+ /// site it was inlined into. Returns false if the function id has already
+ /// been used, and true otherwise.
+ bool recordInlinedCallSiteId(unsigned FuncId, unsigned IAFunc,
+ unsigned IAFile, unsigned IALine,
+ unsigned IACol);
+
+ /// Retreive the function info if this is a valid function id, or nullptr.
+ MCCVFunctionInfo *getCVFunctionInfo(unsigned FuncId) {
+ if (FuncId >= Functions.size())
+ return nullptr;
+ if (Functions[FuncId].isUnallocatedFunctionInfo())
+ return nullptr;
+ return &Functions[FuncId];
+ }
+
/// Saves the information from the currently parsed .cv_loc directive
/// and sets CVLocSeen. When the next instruction is assembled an entry
/// in the line number table with this information and the address of the
@@ -179,10 +249,12 @@ public:
const MCSymbol *FuncBegin,
const MCSymbol *FuncEnd);
- void emitInlineLineTableForFunction(
- MCObjectStreamer &OS, unsigned PrimaryFunctionId, unsigned SourceFileId,
- unsigned SourceLineNum, const MCSymbol *FnStartSym,
- const MCSymbol *FnEndSym, ArrayRef<unsigned> SecondaryFunctionIds);
+ void emitInlineLineTableForFunction(MCObjectStreamer &OS,
+ unsigned PrimaryFunctionId,
+ unsigned SourceFileId,
+ unsigned SourceLineNum,
+ const MCSymbol *FnStartSym,
+ const MCSymbol *FnEndSym);
/// Encodes the binary annotations once we have a layout.
void encodeInlineLineTable(MCAsmLayout &Layout,
@@ -230,6 +302,9 @@ private:
/// A collection of MCCVLineEntry for each section.
std::vector<MCCVLineEntry> MCCVLines;
+
+ /// All known functions and inlined call sites, indexed by function id.
+ std::vector<MCCVFunctionInfo> Functions;
};
} // end namespace llvm
diff --git a/llvm/include/llvm/MC/MCFragment.h b/llvm/include/llvm/MC/MCFragment.h
index 22e90e20aa9..02b73251c84 100644
--- a/llvm/include/llvm/MC/MCFragment.h
+++ b/llvm/include/llvm/MC/MCFragment.h
@@ -491,7 +491,6 @@ class MCCVInlineLineTableFragment : public MCFragment {
unsigned StartLineNum;
const MCSymbol *FnStartSym;
const MCSymbol *FnEndSym;
- SmallVector<unsigned, 3> SecondaryFuncs;
SmallString<8> Contents;
/// CodeViewContext has the real knowledge about this format, so let it access
@@ -502,12 +501,10 @@ public:
MCCVInlineLineTableFragment(unsigned SiteFuncId, unsigned StartFileId,
unsigned StartLineNum, const MCSymbol *FnStartSym,
const MCSymbol *FnEndSym,
- ArrayRef<unsigned> SecondaryFuncs,
MCSection *Sec = nullptr)
: MCFragment(FT_CVInlineLines, false, 0, Sec), SiteFuncId(SiteFuncId),
StartFileId(StartFileId), StartLineNum(StartLineNum),
- FnStartSym(FnStartSym), FnEndSym(FnEndSym),
- SecondaryFuncs(SecondaryFuncs.begin(), SecondaryFuncs.end()) {}
+ FnStartSym(FnStartSym), FnEndSym(FnEndSym) {}
/// \name Accessors
/// @{
diff --git a/llvm/include/llvm/MC/MCObjectStreamer.h b/llvm/include/llvm/MC/MCObjectStreamer.h
index 28c6a414973..0d5389988bb 100644
--- a/llvm/include/llvm/MC/MCObjectStreamer.h
+++ b/llvm/include/llvm/MC/MCObjectStreamer.h
@@ -124,13 +124,14 @@ public:
const MCSymbol *Label);
void EmitCVLocDirective(unsigned FunctionId, unsigned FileNo, unsigned Line,
unsigned Column, bool PrologueEnd, bool IsStmt,
- StringRef FileName) override;
+ StringRef FileName, SMLoc Loc) override;
void EmitCVLinetableDirective(unsigned FunctionId, const MCSymbol *Begin,
const MCSymbol *End) override;
- void EmitCVInlineLinetableDirective(
- unsigned PrimaryFunctionId, unsigned SourceFileId, unsigned SourceLineNum,
- const MCSymbol *FnStartSym, const MCSymbol *FnEndSym,
- ArrayRef<unsigned> SecondaryFunctionIds) override;
+ void EmitCVInlineLinetableDirective(unsigned PrimaryFunctionId,
+ unsigned SourceFileId,
+ unsigned SourceLineNum,
+ const MCSymbol *FnStartSym,
+ const MCSymbol *FnEndSym) override;
void EmitCVDefRangeDirective(
ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
StringRef FixedSizePortion) override;
diff --git a/llvm/include/llvm/MC/MCStreamer.h b/llvm/include/llvm/MC/MCStreamer.h
index e5025400671..99d07ff2003 100644
--- a/llvm/include/llvm/MC/MCStreamer.h
+++ b/llvm/include/llvm/MC/MCStreamer.h
@@ -713,11 +713,20 @@ public:
/// success.
virtual bool EmitCVFileDirective(unsigned FileNo, StringRef Filename);
+ /// \brief Introduces a function id for use with .cv_loc.
+ virtual bool EmitCVFuncIdDirective(unsigned FunctionId);
+
+ /// \brief Introduces an inline call site id for use with .cv_loc. Includes
+ /// extra information for inline line table generation.
+ virtual bool EmitCVInlineSiteIdDirective(unsigned FunctionId, unsigned IAFunc,
+ unsigned IAFile, unsigned IALine,
+ unsigned IACol, SMLoc Loc);
+
/// \brief This implements the CodeView '.cv_loc' assembler directive.
virtual void EmitCVLocDirective(unsigned FunctionId, unsigned FileNo,
unsigned Line, unsigned Column,
bool PrologueEnd, bool IsStmt,
- StringRef FileName);
+ StringRef FileName, SMLoc Loc);
/// \brief This implements the CodeView '.cv_linetable' assembler directive.
virtual void EmitCVLinetableDirective(unsigned FunctionId,
@@ -726,10 +735,11 @@ public:
/// \brief This implements the CodeView '.cv_inline_linetable' assembler
/// directive.
- virtual void EmitCVInlineLinetableDirective(
- unsigned PrimaryFunctionId, unsigned SourceFileId, unsigned SourceLineNum,
- const MCSymbol *FnStartSym, const MCSymbol *FnEndSym,
- ArrayRef<unsigned> SecondaryFunctionIds);
+ virtual void EmitCVInlineLinetableDirective(unsigned PrimaryFunctionId,
+ unsigned SourceFileId,
+ unsigned SourceLineNum,
+ const MCSymbol *FnStartSym,
+ const MCSymbol *FnEndSym);
/// \brief This implements the CodeView '.cv_def_range' assembler
/// directive.
diff --git a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
index 63d9a4744a4..51a5d06b954 100644
--- a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
@@ -124,7 +124,16 @@ CodeViewDebug::getInlineSite(const DILocation *InlinedAt,
auto SiteInsertion = CurFn->InlineSites.insert({InlinedAt, InlineSite()});
InlineSite *Site = &SiteInsertion.first->second;
if (SiteInsertion.second) {
+ unsigned ParentFuncId = CurFn->FuncId;
+ if (const DILocation *OuterIA = InlinedAt->getInlinedAt())
+ ParentFuncId =
+ getInlineSite(OuterIA, InlinedAt->getScope()->getSubprogram())
+ .SiteFuncId;
+
Site->SiteFuncId = NextFuncId++;
+ OS.EmitCVInlineSiteIdDirective(
+ Site->SiteFuncId, ParentFuncId, maybeRecordFile(InlinedAt->getFile()),
+ InlinedAt->getLine(), InlinedAt->getColumn(), SMLoc());
Site->Inlinee = Inlinee;
InlinedSubprograms.insert(Inlinee);
getFuncIdForSubprogram(Inlinee);
@@ -357,8 +366,8 @@ void CodeViewDebug::maybeRecordLocation(const DebugLoc &DL,
}
OS.EmitCVLocDirective(FuncId, FileId, DL.getLine(), DL.getCol(),
- /*PrologueEnd=*/false,
- /*IsStmt=*/false, DL->getFilename());
+ /*PrologueEnd=*/false, /*IsStmt=*/false,
+ DL->getFilename(), SMLoc());
}
void CodeViewDebug::emitCodeViewMagicVersion() {
@@ -529,17 +538,6 @@ void CodeViewDebug::emitInlineeLinesSubsection() {
endCVSubsection(InlineEnd);
}
-void CodeViewDebug::collectInlineSiteChildren(
- SmallVectorImpl<unsigned> &Children, const FunctionInfo &FI,
- const InlineSite &Site) {
- for (const DILocation *ChildSiteLoc : Site.ChildSites) {
- auto I = FI.InlineSites.find(ChildSiteLoc);
- const InlineSite &ChildSite = I->second;
- Children.push_back(ChildSite.SiteFuncId);
- collectInlineSiteChildren(Children, FI, ChildSite);
- }
-}
-
void CodeViewDebug::emitInlinedCallSite(const FunctionInfo &FI,
const DILocation *InlinedAt,
const InlineSite &Site) {
@@ -565,11 +563,9 @@ void CodeViewDebug::emitInlinedCallSite(const FunctionInfo &FI,
unsigned FileId = maybeRecordFile(Site.Inlinee->getFile());
unsigned StartLineNum = Site.Inlinee->getLine();
- SmallVector<unsigned, 3> SecondaryFuncIds;
- collectInlineSiteChildren(SecondaryFuncIds, FI, Site);
OS.EmitCVInlineLinetableDirective(Site.SiteFuncId, FileId, StartLineNum,
- FI.Begin, FI.End, SecondaryFuncIds);
+ FI.Begin, FI.End);
OS.EmitLabel(InlineEnd);
@@ -877,6 +873,8 @@ void CodeViewDebug::beginFunction(const MachineFunction *MF) {
CurFn->FuncId = NextFuncId++;
CurFn->Begin = Asm->getFunctionBegin();
+ OS.EmitCVFuncIdDirective(CurFn->FuncId);
+
// Find the end of the function prolog. First known non-DBG_VALUE and
// non-frame setup location marks the beginning of the function body.
// FIXME: is there a simpler a way to do this? Can we just search
diff --git a/llvm/lib/MC/MCAsmStreamer.cpp b/llvm/lib/MC/MCAsmStreamer.cpp
index 07adfc413d9..7b1c59f1c04 100644
--- a/llvm/lib/MC/MCAsmStreamer.cpp
+++ b/llvm/lib/MC/MCAsmStreamer.cpp
@@ -222,15 +222,20 @@ public:
MCSymbol *getDwarfLineTableSymbol(unsigned CUID) override;
bool EmitCVFileDirective(unsigned FileNo, StringRef Filename) override;
+ bool EmitCVFuncIdDirective(unsigned FuncId) override;
+ bool EmitCVInlineSiteIdDirective(unsigned FunctionId, unsigned IAFunc,
+ unsigned IAFile, unsigned IALine,
+ unsigned IACol, SMLoc Loc) override;
void EmitCVLocDirective(unsigned FunctionId, unsigned FileNo, unsigned Line,
unsigned Column, bool PrologueEnd, bool IsStmt,
- StringRef FileName) override;
+ StringRef FileName, SMLoc Loc) override;
void EmitCVLinetableDirective(unsigned FunctionId, const MCSymbol *FnStart,
const MCSymbol *FnEnd) override;
- void EmitCVInlineLinetableDirective(
- unsigned PrimaryFunctionId, unsigned SourceFileId, unsigned SourceLineNum,
- const MCSymbol *FnStartSym, const MCSymbol *FnEndSym,
- ArrayRef<unsigned> SecondaryFunctionIds) override;
+ void EmitCVInlineLinetableDirective(unsigned PrimaryFunctionId,
+ unsigned SourceFileId,
+ unsigned SourceLineNum,
+ const MCSymbol *FnStartSym,
+ const MCSymbol *FnEndSym) override;
void EmitCVDefRangeDirective(
ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
StringRef FixedSizePortion) override;
@@ -1114,10 +1119,26 @@ bool MCAsmStreamer::EmitCVFileDirective(unsigned FileNo, StringRef Filename) {
return true;
}
+bool MCAsmStreamer::EmitCVFuncIdDirective(unsigned FuncId) {
+ OS << "\t.cv_func_id " << FuncId << '\n';
+ return MCStreamer::EmitCVFuncIdDirective(FuncId);
+}
+
+bool MCAsmStreamer::EmitCVInlineSiteIdDirective(unsigned FunctionId,
+ unsigned IAFunc,
+ unsigned IAFile,
+ unsigned IALine, unsigned IACol,
+ SMLoc Loc) {
+ OS << "\t.cv_inline_site_id " << FunctionId << " within " << IAFunc
+ << " inlined_at " << IAFile << ' ' << IALine << ' ' << IACol << '\n';
+ return MCStreamer::EmitCVInlineSiteIdDirective(FunctionId, IAFunc, IAFile,
+ IALine, IACol, Loc);
+}
+
void MCAsmStreamer::EmitCVLocDirective(unsigned FunctionId, unsigned FileNo,
unsigned Line, unsigned Column,
bool PrologueEnd, bool IsStmt,
- StringRef FileName) {
+ StringRef FileName, SMLoc Loc) {
OS << "\t.cv_loc\t" << FunctionId << " " << FileNo << " " << Line << " "
<< Column;
if (PrologueEnd)
@@ -1135,12 +1156,12 @@ void MCAsmStreamer::EmitCVLocDirective(unsigned FunctionId, unsigned FileNo,
if (IsVerboseAsm) {
OS.PadToColumn(MAI->getCommentColumn());
- OS << MAI->getCommentString() << ' ' << FileName << ':'
- << Line << ':' << Column;
+ OS << MAI->getCommentString() << ' ' << FileName << ':' << Line << ':'
+ << Column;
}
EmitEOL();
this->MCStreamer::EmitCVLocDirective(FunctionId, FileNo, Line, Column,
- PrologueEnd, IsStmt, FileName);
+ PrologueEnd, IsStmt, FileName, Loc);
}
void MCAsmStreamer::EmitCVLinetableDirective(unsigned FunctionId,
@@ -1154,24 +1175,19 @@ void MCAsmStreamer::EmitCVLinetableDirective(unsigned FunctionId,
this->MCStreamer::EmitCVLinetableDirective(FunctionId, FnStart, FnEnd);
}
-void MCAsmStreamer::EmitCVInlineLinetableDirective(
- unsigned PrimaryFunctionId, unsigned SourceFileId, unsigned SourceLineNum,
- const MCSymbol *FnStartSym, const MCSymbol *FnEndSym,
- ArrayRef<unsigned> SecondaryFunctionIds) {
+void MCAsmStreamer::EmitCVInlineLinetableDirective(unsigned PrimaryFunctionId,
+ unsigned SourceFileId,
+ unsigned SourceLineNum,
+ const MCSymbol *FnStartSym,
+ const MCSymbol *FnEndSym) {
OS << "\t.cv_inline_linetable\t" << PrimaryFunctionId << ' ' << SourceFileId
<< ' ' << SourceLineNum << ' ';
FnStartSym->print(OS, MAI);
OS << ' ';
FnEndSym->print(OS, MAI);
- if (!SecondaryFunctionIds.empty()) {
- OS << " contains";
- for (unsigned SecondaryFunctionId : SecondaryFunctionIds)
- OS << ' ' << SecondaryFunctionId;
- }
EmitEOL();
this->MCStreamer::EmitCVInlineLinetableDirective(
- PrimaryFunctionId, SourceFileId, SourceLineNum, FnStartSym, FnEndSym,
- SecondaryFunctionIds);
+ PrimaryFunctionId, SourceFileId, SourceLineNum, FnStartSym, FnEndSym);
}
void MCAsmStreamer::EmitCVDefRangeDirective(
diff --git a/llvm/lib/MC/MCCodeView.cpp b/llvm/lib/MC/MCCodeView.cpp
index b955511a4a7..acea1ecb2b4 100644
--- a/llvm/lib/MC/MCCodeView.cpp
+++ b/llvm/lib/MC/MCCodeView.cpp
@@ -65,6 +65,50 @@ bool CodeViewContext::addFile(unsigned FileNumber, StringRef Filename) {
return true;
}
+bool CodeViewContext::recordFunctionId(unsigned FuncId) {
+ if (FuncId >= Functions.size())
+ Functions.resize(FuncId + 1);
+
+ // Return false if this function info was already allocated.
+ if (!Functions[FuncId].isUnallocatedFunctionInfo())
+ return false;
+
+ // Mark this as an allocated normal function, and leave the rest alone.
+ Functions[FuncId].ParentFuncIdPlusOne = MCCVFunctionInfo::FunctionSentinel;
+ return true;
+}
+
+bool CodeViewContext::recordInlinedCallSiteId(unsigned FuncId, unsigned IAFunc,
+ unsigned IAFile, unsigned IALine,
+ unsigned IACol) {
+ if (FuncId >= Functions.size())
+ Functions.resize(FuncId + 1);
+
+ // Return false if this function info was already allocated.
+ if (!Functions[FuncId].isUnallocatedFunctionInfo())
+ return false;
+
+ MCCVFunctionInfo::LineInfo InlinedAt;
+ InlinedAt.File = IAFile;
+ InlinedAt.Line = IALine;
+ InlinedAt.Col = IACol;
+
+ // Mark this as an inlined call site and record call site line info.
+ MCCVFunctionInfo *Info = &Functions[FuncId];
+ Info->ParentFuncIdPlusOne = IAFunc + 1;
+ Info->InlinedAt = InlinedAt;
+
+ // Walk up the call chain adding this function id to the InlinedAtMap of all
+ // transitive callers until we hit a real function.
+ while (Info->isInlinedCallSite()) {
+ InlinedAt = Info->InlinedAt;
+ Info = getCVFunctionInfo(Info->getParentFuncId());
+ Info->InlinedAtMap[FuncId] = InlinedAt;
+ }
+
+ return true;
+}
+
MCDataFragment *CodeViewContext::getStringTableFragment() {
if (!StrTabFragment) {
StrTabFragment = new MCDataFragment();
@@ -237,15 +281,17 @@ static uint32_t encodeSignedNumber(uint32_t Data) {
return Data << 1;
}
-void CodeViewContext::emitInlineLineTableForFunction(
- MCObjectStreamer &OS, unsigned PrimaryFunctionId, unsigned SourceFileId,
- unsigned SourceLineNum, const MCSymbol *FnStartSym,
- const MCSymbol *FnEndSym, ArrayRef<unsigned> SecondaryFunctionIds) {
+void CodeViewContext::emitInlineLineTableForFunction(MCObjectStreamer &OS,
+ unsigned PrimaryFunctionId,
+ unsigned SourceFileId,
+ unsigned SourceLineNum,
+ const MCSymbol *FnStartSym,
+ const MCSymbol *FnEndSym) {
// Create and insert a fragment into the current section that will be encoded
// later.
- new MCCVInlineLineTableFragment(
- PrimaryFunctionId, SourceFileId, SourceLineNum, FnStartSym, FnEndSym,
- SecondaryFunctionIds, OS.getCurrentSectionOnly());
+ new MCCVInlineLineTableFragment(PrimaryFunctionId, SourceFileId,
+ SourceLineNum, FnStartSym, FnEndSym,
+ OS.getCurrentSectionOnly());
}
void CodeViewContext::emitDefRange(
@@ -280,69 +326,83 @@ void CodeViewContext::encodeInlineLineTable(MCAsmLayout &Layout,
size_t LocBegin;
size_t LocEnd;
std::tie(LocBegin, LocEnd) = getLineExtent(Frag.SiteFuncId);
- for (unsigned SecondaryId : Frag.SecondaryFuncs) {
- auto Extent = getLineExtent(SecondaryId);
+
+ // Include all child inline call sites in our .cv_loc extent.
+ MCCVFunctionInfo *SiteInfo = getCVFunctionInfo(Frag.SiteFuncId);
+ for (auto &KV : SiteInfo->InlinedAtMap) {
+ unsigned ChildId = KV.first;
+ auto Extent = getLineExtent(ChildId);
LocBegin = std::min(LocBegin, Extent.first);
LocEnd = std::max(LocEnd, Extent.second);
}
+
if (LocBegin >= LocEnd)
return;
ArrayRef<MCCVLineEntry> Locs = getLinesForExtent(LocBegin, LocEnd);
if (Locs.empty())
return;
- SmallSet<unsigned, 8> InlinedFuncIds;
- InlinedFuncIds.insert(Frag.SiteFuncId);
- InlinedFuncIds.insert(Frag.SecondaryFuncs.begin(), Frag.SecondaryFuncs.end());
-
// Make an artificial start location using the function start and the inlinee
// lines start location information. All deltas start relative to this
// location.
MCCVLineEntry StartLoc(Frag.getFnStartSym(), MCCVLoc(Locs.front()));
StartLoc.setFileNum(Frag.StartFileId);
StartLoc.setLine(Frag.StartLineNum);
- const MCCVLineEntry *LastLoc = &StartLoc;
bool HaveOpenRange = false;
+ const MCSymbol *LastLabel = Frag.getFnStartSym();
+ MCCVFunctionInfo::LineInfo LastSourceLoc, CurSourceLoc;
+ LastSourceLoc.File = Frag.StartFileId;
+ LastSourceLoc.Line = Frag.StartLineNum;
+
SmallVectorImpl<char> &Buffer = Frag.getContents();
Buffer.clear(); // Clear old contents if we went through relaxation.
for (const MCCVLineEntry &Loc : Locs) {
- if (!InlinedFuncIds.count(Loc.getFunctionId())) {
- // We've hit a cv_loc not attributed to this inline call site. Use this
- // label to end the PC range.
- if (HaveOpenRange) {
- unsigned Length =
- computeLabelDiff(Layout, LastLoc->getLabel(), Loc.getLabel());
- compressAnnotation(BinaryAnnotationsOpCode::ChangeCodeLength, Buffer);
- compressAnnotation(Length, Buffer);
+ if (Loc.getFunctionId() == Frag.SiteFuncId) {
+ CurSourceLoc.File = Loc.getFileNum();
+ CurSourceLoc.Line = Loc.getLine();
+ } else {
+ auto I = SiteInfo->InlinedAtMap.find(Loc.getFunctionId());
+ if (I != SiteInfo->InlinedAtMap.end()) {
+ // This .cv_loc is from a child inline call site. Use the source
+ // location of the inlined call site instead of the .cv_loc directive
+ // source location.
+ CurSourceLoc = I->second;
+ } else {
+ // We've hit a cv_loc not attributed to this inline call site. Use this
+ // label to end the PC range.
+ if (HaveOpenRange) {
+ unsigned Length = computeLabelDiff(Layout, LastLabel, Loc.getLabel());
+ compressAnnotation(BinaryAnnotationsOpCode::ChangeCodeLength, Buffer);
+ compressAnnotation(Length, Buffer);
+ LastLabel = Loc.getLabel();
+ }
+ HaveOpenRange = false;
+ continue;
}
- HaveOpenRange = false;
- continue;
}
- // If we've already opened the function and we're at an indirectly inlined
- // location, continue until the next directly inlined location.
- bool DirectlyInlined = Loc.getFunctionId() == Frag.SiteFuncId;
- if (!DirectlyInlined && HaveOpenRange)
+ // Skip this .cv_loc if we have an open range and this isn't a meaningful
+ // source location update. The current table format does not support column
+ // info, so we can skip updates for those.
+ if (HaveOpenRange && CurSourceLoc.File == LastSourceLoc.File &&
+ CurSourceLoc.Line == LastSourceLoc.Line)
continue;
+
HaveOpenRange = true;
- if (Loc.getFileNum() != LastLoc->getFileNum()) {
+ if (CurSourceLoc.File != LastSourceLoc.File) {
// File ids are 1 based, and each file checksum table entry is 8 bytes
// long. See emitFileChecksums above.
- unsigned FileOffset = 8 * (Loc.getFileNum() - 1);
+ unsigned FileOffset = 8 * (CurSourceLoc.File - 1);
compressAnnotation(BinaryAnnotationsOpCode::ChangeFile, Buffer);
compressAnnotation(FileOffset, Buffer);
}
- int LineDelta = Loc.getLine() - LastLoc->getLine();
- if (LineDelta == 0)
- continue;
-
+ int LineDelta = CurSourceLoc.Line - LastSourceLoc.Line;
unsigned EncodedLineDelta = encodeSignedNumber(LineDelta);
- unsigned CodeDelta =
- computeLabelDiff(Layout, LastLoc->getLabel(), Loc.getLabel());
- if (CodeDelta == 0) {
+ unsigned CodeDelta = computeLabelDiff(Layout, LastLabel, Loc.getLabel());
+ if (CodeDelta == 0 && LineDelta != 0) {
compressAnnotation(BinaryAnnotationsOpCode::ChangeLineOffset, Buffer);
compressAnnotation(EncodedLineDelta, Buffer);
} else if (EncodedLineDelta < 0x8 && CodeDelta <= 0xf) {
@@ -355,29 +415,29 @@ void CodeViewContext::encodeInlineLineTable(MCAsmLayout &Layout,
compressAnnotation(Operand, Buffer);
} else {
// Otherwise use the separate line and code deltas.
- compressAnnotation(BinaryAnnotationsOpCode::ChangeLineOffset, Buffer);
- compressAnnotation(EncodedLineDelta, Buffer);
+ if (LineDelta != 0) {
+ compressAnnotation(BinaryAnnotationsOpCode::ChangeLineOffset, Buffer);
+ compressAnnotation(EncodedLineDelta, Buffer);
+ }
compressAnnotation(BinaryAnnotationsOpCode::ChangeCodeOffset, Buffer);
compressAnnotation(CodeDelta, Buffer);
}
- LastLoc = &Loc;
+ LastLabel = Loc.getLabel();
+ LastSourceLoc = CurSourceLoc;
}
assert(HaveOpenRange);
unsigned EndSymLength =
- computeLabelDiff(Layout, LastLoc->getLabel(), Frag.getFnEndSym());
+ computeLabelDiff(Layout, LastLabel, Frag.getFnEndSym());
unsigned LocAfterLength = ~0U;
ArrayRef<MCCVLineEntry> LocAfter = getLinesForExtent(LocEnd, LocEnd + 1);
if (!LocAfter.empty()) {
// Only try to compute this difference if we're in the same section.
const MCCVLineEntry &Loc = LocAfter[0];
- if (&Loc.getLabel()->getSection(false) ==
- &LastLoc->getLabel()->getSection(false)) {
- LocAfterLength =
- computeLabelDiff(Layout, LastLoc->getLabel(), Loc.getLabel());
- }
+ if (&Loc.getLabel()->getSection(false) == &LastLabel->getSection(false))
+ LocAfterLength = computeLabelDiff(Layout, LastLabel, Loc.getLabel());
}
compressAnnotation(BinaryAnnotationsOpCode::ChangeCodeLength, Buffer);
diff --git a/llvm/lib/MC/MCObjectStreamer.cpp b/llvm/lib/MC/MCObjectStreamer.cpp
index e86a0e1dcf9..f4cb09494d0 100644
--- a/llvm/lib/MC/MCObjectStreamer.cpp
+++ b/llvm/lib/MC/MCObjectStreamer.cpp
@@ -369,13 +369,13 @@ void MCObjectStreamer::EmitDwarfAdvanceFrameAddr(const MCSymbol *LastLabel,
void MCObjectStreamer::EmitCVLocDirective(unsigned FunctionId, unsigned FileNo,
unsigned Line, unsigned Column,
bool PrologueEnd, bool IsStmt,
- StringRef FileName) {
+ StringRef FileName, SMLoc Loc) {
// In case we see two .cv_loc directives in a row, make sure the
// first one gets a line entry.
MCCVLineEntry::Make(this);
this->MCStreamer::EmitCVLocDirective(FunctionId, FileNo, Line, Column,
- PrologueEnd, IsStmt, FileName);
+ PrologueEnd, IsStmt, FileName, Loc);
}
void MCObjectStreamer::EmitCVLinetableDirective(unsigned FunctionId,
@@ -388,14 +388,12 @@ void MCObjectStreamer::EmitCVLinetableDirective(unsigned FunctionId,
void MCObjectStreamer::EmitCVInlineLinetableDirective(
unsigned PrimaryFunctionId, unsigned SourceFileId, unsigned SourceLineNum,
- const MCSymbol *FnStartSym, const MCSymbol *FnEndSym,
- ArrayRef<unsigned> SecondaryFunctionIds) {
+ const MCSymbol *FnStartSym, const MCSymbol *FnEndSym) {
getContext().getCVContext().emitInlineLineTableForFunction(
*this, PrimaryFunctionId, SourceFileId, SourceLineNum, FnStartSym,
- FnEndSym, SecondaryFunctionIds);
+ FnEndSym);
this->MCStreamer::EmitCVInlineLinetableDirective(
- PrimaryFunctionId, SourceFileId, SourceLineNum, FnStartSym, FnEndSym,
- SecondaryFunctionIds);
+ PrimaryFunctionId, SourceFileId, SourceLineNum, FnStartSym, FnEndSym);
}
void MCObjectStreamer::EmitCVDefRangeDirective(
diff --git a/llvm/lib/MC/MCParser/AsmParser.cpp b/llvm/lib/MC/MCParser/AsmParser.cpp
index 43c88c96860..a75818e99cd 100644
--- a/llvm/lib/MC/MCParser/AsmParser.cpp
+++ b/llvm/lib/MC/MCParser/AsmParser.cpp
@@ -378,6 +378,9 @@ private:
bool parseRegisterOrRegisterNumber(int64_t &Register, SMLoc DirectiveLoc);
+ bool parseCVFunctionId(int64_t &FunctionId, StringRef DirectiveName);
+ bool parseCVFileId(int64_t &FileId, StringRef DirectiveName);
+
// Generic (target and platform independent) directive parsing.
enum DirectiveKind {
DK_NO_DIRECTIVE, // Placeholder
@@ -397,8 +400,9 @@ private:
DK_IFNB, DK_IFC, DK_IFEQS, DK_IFNC, DK_IFNES, DK_IFDEF, DK_IFNDEF,
DK_IFNOTDEF, DK_ELSEIF, DK_ELSE, DK_ENDIF,
DK_SPACE, DK_SKIP, DK_FILE, DK_LINE, DK_LOC, DK_STABS,
- DK_CV_FILE, DK_CV_LOC, DK_CV_LINETABLE, DK_CV_INLINE_LINETABLE,
- DK_CV_DEF_RANGE, DK_CV_STRINGTABLE, DK_CV_FILECHECKSUMS,
+ DK_CV_FILE, DK_CV_FUNC_ID, DK_CV_INLINE_SITE_ID, DK_CV_LOC, DK_CV_LINETABLE,
+ DK_CV_INLINE_LINETABLE, DK_CV_DEF_RANGE, DK_CV_STRINGTABLE,
+ DK_CV_FILECHECKSUMS,
DK_CFI_SECTIONS, DK_CFI_STARTPROC, DK_CFI_ENDPROC, DK_CFI_DEF_CFA,
DK_CFI_DEF_CFA_OFFSET, DK_CFI_ADJUST_CFA_OFFSET, DK_CFI_DEF_CFA_REGISTER,
DK_CFI_OFFSET, DK_CFI_REL_OFFSET, DK_CFI_PERSONALITY, DK_CFI_LSDA,
@@ -436,9 +440,11 @@ private:
bool parseDirectiveLoc();
bool parseDirectiveStabs();
- // ".cv_file", ".cv_loc", ".cv_linetable", "cv_inline_linetable",
- // ".cv_def_range"
+ // ".cv_file", ".cv_func_id", ".cv_inline_site_id", ".cv_loc", ".cv_linetable",
+ // ".cv_inline_linetable", ".cv_def_range"
bool parseDirectiveCVFile();
+ bool parseDirectiveCVFuncId();
+ bool parseDirectiveCVInlineSiteId();
bool parseDirectiveCVLoc();
bool parseDirectiveCVLinetable();
bool parseDirectiveCVInlineLinetable();
@@ -1790,6 +1796,10 @@ bool AsmParser::parseStatement(ParseStatementInfo &Info,
return parseDirectiveStabs();
case DK_CV_FILE:
return parseDirectiveCVFile();
+ case DK_CV_FUNC_ID:
+ return parseDirectiveCVFuncId();
+ case DK_CV_INLINE_SITE_ID:
+ return parseDirectiveCVInlineSiteId();
case DK_CV_LOC:
return parseDirectiveCVLoc();
case DK_CV_LINETABLE:
@@ -3240,6 +3250,107 @@ bool AsmParser::parseDirectiveCVFile() {
return false;
}
+bool AsmParser::parseCVFunctionId(int64_t &FunctionId,
+ StringRef DirectiveName) {
+ SMLoc Loc;
+ return parseTokenLoc(Loc) ||
+ parseIntToken(FunctionId, "expected function id in '" + DirectiveName +
+ "' directive") ||
+ check(FunctionId < 0 || FunctionId >= UINT_MAX, Loc,
+ "expected function id within range [0, UINT_MAX)");
+}
+
+bool AsmParser::parseCVFileId(int64_t &FileNumber, StringRef DirectiveName) {
+ SMLoc Loc;
+ return parseTokenLoc(Loc) ||
+ parseIntToken(FileNumber, "expected integer in '" + DirectiveName +
+ "' directive") ||
+ check(FileNumber < 1, Loc, "file number less than one in '" +
+ DirectiveName + "' directive") ||
+ check(!getCVContext().isValidFileNumber(FileNumber), Loc,
+ "unassigned file number in '" + DirectiveName + "' directive");
+}
+
+/// parseDirectiveCVFuncId
+/// ::= .cv_func_id FunctionId
+///
+/// Introduces a function ID that can be used with .cv_loc.
+bool AsmParser::parseDirectiveCVFuncId() {
+ SMLoc FunctionIdLoc = getTok().getLoc();
+ int64_t FunctionId;
+
+ if (parseCVFunctionId(FunctionId, ".cv_func_id") ||
+ parseToken(AsmToken::EndOfStatement,
+ "unexpected token in '.cv_func_id' directive"))
+ return true;
+
+ if (!getStreamer().EmitCVFuncIdDirective(FunctionId))
+ Error(FunctionIdLoc, "function id already allocated");
+
+ return false;
+}
+
+/// parseDirectiveCVInlineSiteId
+/// ::= .cv_inline_site_id FunctionId
+/// "within" IAFunc
+/// "inlined_at" IAFile IALine [IACol]
+///
+/// Introduces a function ID that can be used with .cv_loc. Includes "inlined
+/// at" source location information for use in the line table of the caller,
+/// whether the caller is a real function or another inlined call site.
+bool AsmParser::parseDirectiveCVInlineSiteId() {
+ SMLoc FunctionIdLoc = getTok().getLoc();
+ int64_t FunctionId;
+ int64_t IAFunc;
+ int64_t IAFile;
+ int64_t IALine;
+ int64_t IACol = 0;
+
+ // FunctionId
+ if (parseCVFunctionId(FunctionId, ".cv_inline_site_id"))
+ return true;
+
+ // "within"
+ if (check((getLexer().isNot(AsmToken::Identifier) ||
+ getTok().getIdentifier() != "within"),
+ "expected 'within' identifier in '.cv_inline_site_id' directive"))
+ return true;
+ Lex();
+
+ // IAFunc
+ if (parseCVFunctionId(IAFunc, ".cv_inline_site_id"))
+ return true;
+
+ // "inlined_at"
+ if (check((getLexer().isNot(AsmToken::Identifier) ||
+ getTok().getIdentifier() != "inlined_at"),
+ "expected 'inlined_at' identifier in '.cv_inline_site_id' "
+ "directive") )
+ return true;
+ Lex();
+
+ // IAFile IALine
+ if (parseCVFileId(IAFile, ".cv_inline_site_id") ||
+ parseIntToken(IALine, "expected line number after 'inlined_at'"))
+ return true;
+
+ // [IACol]
+ if (getLexer().is(AsmToken::Integer)) {
+ IACol = getTok().getIntVal();
+ Lex();
+ }
+
+ if (parseToken(AsmToken::EndOfStatement,
+ "unexpected token in '.cv_inline_site_id' directive"))
+ return true;
+
+ if (!getStreamer().EmitCVInlineSiteIdDirective(FunctionId, IAFunc, IAFile,
+ IALine, IACol, FunctionIdLoc))
+ Error(FunctionIdLoc, "function id already allocated");
+
+ return false;
+}
+
/// parseDirectiveCVLoc
/// ::= .cv_loc FunctionId FileNumber [LineNumber] [ColumnPos] [prologue_end]
/// [is_stmt VALUE]
@@ -3248,18 +3359,11 @@ bool AsmParser::parseDirectiveCVFile() {
/// third number is a column position (zero if not specified). The remaining
/// optional items are .loc sub-directives.
bool AsmParser::parseDirectiveCVLoc() {
+ SMLoc DirectiveLoc = getTok().getLoc();
SMLoc Loc;
int64_t FunctionId, FileNumber;
- if (parseTokenLoc(Loc) ||
- parseIntToken(FunctionId, "unexpected token in '.cv_loc' directive") ||
- check(FunctionId < 0, Loc,
- "function id less than zero in '.cv_loc' directive") ||
- parseTokenLoc(Loc) ||
- parseIntToken(FileNumber, "expected integer in '.cv_loc' directive") ||
- check(FileNumber < 1, Loc,
- "file number less than one in '.cv_loc' directive") ||
- check(!getCVContext().isValidFileNumber(FileNumber), Loc,
- "unassigned file number in '.cv_loc' directive"))
+ if (parseCVFunctionId(FunctionId, ".cv_loc") ||
+ parseCVFileId(FileNumber, ".cv_loc"))
return true;
int64_t LineNumber = 0;
@@ -3307,7 +3411,8 @@ bool AsmParser::parseDirectiveCVLoc() {
Lex();
getStreamer().EmitCVLocDirective(FunctionId, FileNumber, LineNumber,
- ColumnPos, PrologueEnd, IsStmt, StringRef());
+ ColumnPos, PrologueEnd, IsStmt, StringRef(),
+ DirectiveLoc);
return false;
}
@@ -3317,10 +3422,7 @@ bool AsmParser::parseDirectiveCVLinetable() {
int64_t FunctionId;
StringRef FnStartName, FnEndName;
SMLoc Loc = getTok().getLoc();
- if (parseIntToken(FunctionId,
- "expected Integer in '.cv_linetable' directive") ||
- check(FunctionId < 0, Loc,
- "function id less than zero in '.cv_linetable' directive") ||
+ if (parseCVFunctionId(FunctionId, ".cv_linetable") ||
parseToken(AsmToken::Comma,
"unexpected token in '.cv_linetable' directive") ||
parseTokenLoc(Loc) || check(parseIdentifier(FnStartName), Loc,
@@ -3340,16 +3442,11 @@ bool AsmParser::parseDirectiveCVLinetable() {
/// parseDirectiveCVInlineLinetable
/// ::= .cv_inline_linetable PrimaryFunctionId FileId LineNum FnStart FnEnd
-/// ("contains" SecondaryFunctionId+)?
bool AsmParser::parseDirectiveCVInlineLinetable() {
int64_t PrimaryFunctionId, SourceFileId, SourceLineNum;
StringRef FnStartName, FnEndName;
SMLoc Loc = getTok().getLoc();
- if (parseIntToken(
- PrimaryFunctionId,
- "expected PrimaryFunctionId in '.cv_inline_linetable' directive") ||
- check(PrimaryFunctionId < 0, Loc,
- "function id less than zero in '.cv_inline_linetable' directive") ||
+ if (parseCVFunctionId(PrimaryFunctionId, ".cv_inline_linetable") ||
parseTokenLoc(Loc) ||
parseIntToken(
SourceFileId,
@@ -3368,24 +3465,6 @@ bool AsmParser::parseDirectiveCVInlineLinetable() {
"expected identifier in directive"))
return true;
- SmallVector<unsigned, 8> SecondaryFunctionIds;
- if (getLexer().is(AsmToken::Identifier)) {
- if (getTok().getIdentifier() != "contains")
- return TokError(
- "unexpected identifier in '.cv_inline_linetable' directive");
- Lex();
-
- while (getLexer().isNot(AsmToken::EndOfStatement)) {
- int64_t SecondaryFunctionId = getTok().getIntVal();
- if (SecondaryFunctionId < 0)
- return TokError(
- "function id less than zero in '.cv_inline_linetable' directive");
- Lex();
-
- SecondaryFunctionIds.push_back(SecondaryFunctionId);
- }
- }
-
if (parseToken(AsmToken::EndOfStatement, "Expected End of Statement"))
return true;
@@ -3393,7 +3472,7 @@ bool AsmParser::parseDirectiveCVInlineLinetable() {
MCSymbol *FnEndSym = getContext().getOrCreateSymbol(FnEndName);
getStreamer().EmitCVInlineLinetableDirective(PrimaryFunctionId, SourceFileId,
SourceLineNum, FnStartSym,
- FnEndSym, SecondaryFunctionIds);
+ FnEndSym);
return false;
}
@@ -4701,9 +4780,11 @@ void AsmParser::initializeDirectiveKindMap() {
DirectiveKindMap[".loc"] = DK_LOC;
DirectiveKindMap[".stabs"] = DK_STABS;
DirectiveKindMap[".cv_file"] = DK_CV_FILE;
+ DirectiveKindMap[".cv_func_id"] = DK_CV_FUNC_ID;
DirectiveKindMap[".cv_loc"] = DK_CV_LOC;
DirectiveKindMap[".cv_linetable"] = DK_CV_LINETABLE;
DirectiveKindMap[".cv_inline_linetable"] = DK_CV_INLINE_LINETABLE;
+ DirectiveKindMap[".cv_inline_site_id"] = DK_CV_INLINE_SITE_ID;
DirectiveKindMap[".cv_def_range"] = DK_CV_DEF_RANGE;
DirectiveKindMap[".cv_stringtable"] = DK_CV_STRINGTABLE;
DirectiveKindMap[".cv_filechecksums"] = DK_CV_FILECHECKSUMS;
diff --git a/llvm/lib/MC/MCStreamer.cpp b/llvm/lib/MC/MCStreamer.cpp
index ca244126dcd..124a1911a9a 100644
--- a/llvm/lib/MC/MCStreamer.cpp
+++ b/llvm/lib/MC/MCStreamer.cpp
@@ -220,22 +220,54 @@ bool MCStreamer::EmitCVFileDirective(unsigned FileNo, StringRef Filename) {
return getContext().getCVContext().addFile(FileNo, Filename);
}
+bool MCStreamer::EmitCVFuncIdDirective(unsigned FunctionId) {
+ return getContext().getCVContext().recordFunctionId(FunctionId);
+}
+
+bool MCStreamer::EmitCVInlineSiteIdDirective(unsigned FunctionId,
+ unsigned IAFunc, unsigned IAFile,
+ unsigned IALine, unsigned IACol,
+ SMLoc Loc) {
+ if (getContext().getCVContext().getCVFunctionInfo(IAFunc) == nullptr) {
+ getContext().reportError(Loc, "parent function id not introduced by "
+ ".cv_func_id or .cv_inline_site_id");
+ return true;
+ }
+
+ return getContext().getCVContext().recordInlinedCallSiteId(
+ FunctionId, IAFunc, IAFile, IALine, IACol);
+}
+
void MCStreamer::EmitCVLocDirective(unsigned FunctionId, unsigned FileNo,
unsigned Line, unsigned Column,
bool PrologueEnd, bool IsStmt,
- StringRef FileName) {
- getContext().getCVContext().setCurrentCVLoc(FunctionId, FileNo, Line, Column,
- PrologueEnd, IsStmt);
+ StringRef FileName, SMLoc Loc) {
+ CodeViewContext &CVC = getContext().getCVContext();
+ MCCVFunctionInfo *FI = CVC.getCVFunctionInfo(FunctionId);
+ if (!FI)
+ return getContext().reportError(
+ Loc, "function id not introduced by .cv_func_id or .cv_inline_site_id");
+
+ // Track the section
+ if (FI->Section == nullptr)
+ FI->Section = getCurrentSectionOnly();
+ else if (FI->Section != getCurrentSectionOnly())
+ return getContext().reportError(
+ Loc,
+ "all .cv_loc directives for a function must be in the same section");
+
+ CVC.setCurrentCVLoc(FunctionId, FileNo, Line, Column, PrologueEnd, IsStmt);
}
void MCStreamer::EmitCVLinetableDirective(unsigned FunctionId,
const MCSymbol *Begin,
const MCSymbol *End) {}
-void MCStreamer::EmitCVInlineLinetableDirective(
- unsigned PrimaryFunctionId, unsigned SourceFileId, unsigned SourceLineNum,
- const MCSymbol *FnStartSym, const MCSymbol *FnEndSym,
- ArrayRef<unsigned> SecondaryFunctionIds) {}
+void MCStreamer::EmitCVInlineLinetableDirective(unsigned PrimaryFunctionId,
+ unsigned SourceFileId,
+ unsigned SourceLineNum,
+ const MCSymbol *FnStartSym,
+ const MCSymbol *FnEndSym) {}
void MCStreamer::EmitCVDefRangeDirective(
ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
diff --git a/llvm/test/DebugInfo/COFF/inlining-header.ll b/llvm/test/DebugInfo/COFF/inlining-header.ll
index 6a57e182a32..143bd48e4be 100644
--- a/llvm/test/DebugInfo/COFF/inlining-header.ll
+++ b/llvm/test/DebugInfo/COFF/inlining-header.ll
@@ -25,13 +25,16 @@
; ASM: _main: # @main
; ASM: Lfunc_begin0:
+; ASM: .cv_func_id 0
; ASM: # BB#0: # %entry
; ASM: .cv_file 1 "D:\\src\\llvm\\build\\t.cpp"
; ASM: .cv_loc 0 1 9 5 is_stmt 0 # t.cpp:9:5
; ASM: incl "?x@@3HC"
+; ASM: .cv_inline_site_id 1 within 0 inlined_at 1 10 3
; ASM: .cv_loc 1 1 4 5 # t.cpp:4:5
; ASM: addl $2, "?x@@3HC"
; ASM: .cv_file 2 "D:\\src\\llvm\\build\\t.h"
+; ASM: .cv_inline_site_id 2 within 1 inlined_at 1 5 3
; ASM: .cv_loc 2 2 2 5 # ./t.h:2:5
; ASM: addl $3, "?x@@3HC"
; ASM: .cv_loc 1 1 6 5 # t.cpp:6:5
@@ -61,7 +64,6 @@
; OBJ: Subsection [
; OBJ: SubSectionType: Symbols (0xF1)
-; OBJ: SubSectionSize: 0x62
; OBJ: ProcStart {
; OBJ: Kind: S_GPROC32_ID (0x1147)
; OBJ: FunctionType: main (0x1005)
@@ -78,7 +80,8 @@
; OBJ: Inlinee: g (0x1002)
; OBJ: BinaryAnnotations [
; OBJ-NEXT: ChangeCodeOffsetAndLineOffset: {CodeOffset: 0x6, LineOffset: 1}
-; OBJ-NEXT: ChangeCodeOffsetAndLineOffset: {CodeOffset: 0xE, LineOffset: 2}
+; OBJ-NEXT: ChangeCodeOffsetAndLineOffset: {CodeOffset: 0x7, LineOffset: 1}
+; OBJ-NEXT: ChangeCodeOffsetAndLineOffset: {CodeOffset: 0x7, LineOffset: 1}
; OBJ-NEXT: ChangeCodeLength: 0x7
; OBJ-NEXT: ]
; OBJ: }
diff --git a/llvm/test/DebugInfo/COFF/inlining-levels.ll b/llvm/test/DebugInfo/COFF/inlining-levels.ll
index 2c25670dee5..55ce3de8479 100644
--- a/llvm/test/DebugInfo/COFF/inlining-levels.ll
+++ b/llvm/test/DebugInfo/COFF/inlining-levels.ll
@@ -20,13 +20,13 @@
; OBJ: SubSectionType: Symbols (0xF1)
; OBJ: ProcStart {
; OBJ: InlineSite {
-; OBJ: Inlinee: h (0x1004)
+; OBJ: Inlinee: h (0x1002)
; OBJ: }
; OBJ: InlineSite {
; OBJ: Inlinee: g (0x1003)
; OBJ: }
; OBJ: InlineSite {
-; OBJ: Inlinee: f (0x1002)
+; OBJ: Inlinee: f (0x1004)
; OBJ: }
; OBJ: InlineSiteEnd {
; OBJ: }
diff --git a/llvm/test/DebugInfo/COFF/inlining.ll b/llvm/test/DebugInfo/COFF/inlining.ll
index 815111f9cbf..9ca4c4120a0 100644
--- a/llvm/test/DebugInfo/COFF/inlining.ll
+++ b/llvm/test/DebugInfo/COFF/inlining.ll
@@ -21,11 +21,14 @@
; 16: x += 7;
; 17: }
+; ASM: .cv_func_id 0
; ASM: .cv_loc 0 1 13 0 is_stmt 0 # t.cpp:13:0
; ASM: .cv_loc 0 1 14 5 # t.cpp:14:5
; ASM: addl $6, "?x@@3HC"
+; ASM: .cv_inline_site_id 1 within 0 inlined_at 1 15 3
; ASM: .cv_loc 1 1 9 5 # t.cpp:9:5
; ASM: addl $4, "?x@@3HC"
+; ASM: .cv_inline_site_id 2 within 1 inlined_at 1 10 3
; ASM: .cv_loc 2 1 3 7 # t.cpp:3:7
; ASM: .cv_loc 2 1 4 5 # t.cpp:4:5
; ASM: addl {{.*}}, "?x@@3HC"
@@ -60,7 +63,7 @@
; ASM: .long
; ASM: .long
; ASM: .long
-; ASM: .cv_inline_linetable 1 1 8 Lfunc_begin0 Lfunc_end0 contains 2
+; ASM: .cv_inline_linetable 1 1 8 Lfunc_begin0 Lfunc_end0
; ASM: .short 4429
; ASM: .long
; ASM: .long
@@ -184,8 +187,9 @@
; OBJ: Inlinee: bar (0x1002)
; OBJ: BinaryAnnotations [
; OBJ-NEXT: ChangeCodeOffsetAndLineOffset: {CodeOffset: 0x8, LineOffset: 1}
-; OBJ-NEXT: ChangeLineOffset: 2
-; OBJ-NEXT: ChangeCodeOffset: 0x25
+; OBJ-NEXT: ChangeCodeOffsetAndLineOffset: {CodeOffset: 0x7, LineOffset: 1}
+; OBJ-NEXT: ChangeLineOffset: 1
+; OBJ-NEXT: ChangeCodeOffset: 0x1E
; OBJ-NEXT: ChangeCodeLength: 0x7
; OBJ: ]
; OBJ: }
diff --git a/llvm/test/DebugInfo/COFF/local-variables.ll b/llvm/test/DebugInfo/COFF/local-variables.ll
index 86356fdde45..2c3fd89a9d4 100644
--- a/llvm/test/DebugInfo/COFF/local-variables.ll
+++ b/llvm/test/DebugInfo/COFF/local-variables.ll
@@ -22,6 +22,7 @@
; 17: }
; ASM: f: # @f
+; ASM: .cv_func_id 0
; ASM: .cv_file 1 "D:\\src\\llvm\\build\\t.cpp"
; ASM: .cv_loc 0 1 7 0 is_stmt 0 # t.cpp:7:0
; ASM: .seh_proc f
@@ -40,6 +41,7 @@
; ASM: .cv_loc 0 1 9 9 # t.cpp:9:9
; ASM: movl $42, 40(%rsp)
; ASM: [[inline_site1:\.Ltmp.*]]:
+; ASM: .cv_inline_site_id 1 within 0 inlined_at 1 10 5
; ASM: .cv_loc 1 1 4 7 # t.cpp:4:7
; ASM: movl $3, 44(%rsp)
; ASM: leaq 44(%rsp), %rcx
@@ -54,6 +56,7 @@
; ASM: .cv_loc 0 1 13 9 # t.cpp:13:9
; ASM: movl $42, 36(%rsp)
; ASM: [[inline_site2:\.Ltmp.*]]:
+; ASM: .cv_inline_site_id 2 within 0 inlined_at 1 14 5
; ASM: .cv_loc 2 1 4 7 # t.cpp:4:7
; ASM: movl $3, 48(%rsp)
; ASM: leaq 48(%rsp), %rcx
diff --git a/llvm/test/MC/COFF/cv-def-range.s b/llvm/test/MC/COFF/cv-def-range.s
index a1ae1404e92..5ac0df7f7d9 100644
--- a/llvm/test/MC/COFF/cv-def-range.s
+++ b/llvm/test/MC/COFF/cv-def-range.s
@@ -15,6 +15,7 @@
_g: # @g
Lfunc_begin0:
.cv_file 1 "\\usr\\local\\google\\home\\majnemer\\llvm\\src\\<stdin>"
+ .cv_func_id 0
.cv_loc 0 1 3 0 is_stmt 0 # <stdin>:3:0
# BB#0: # %entry
pushl %ebp
diff --git a/llvm/test/MC/COFF/cv-empty-linetable.s b/llvm/test/MC/COFF/cv-empty-linetable.s
index 4fcafd2d268..568d55a3657 100644
--- a/llvm/test/MC/COFF/cv-empty-linetable.s
+++ b/llvm/test/MC/COFF/cv-empty-linetable.s
@@ -16,6 +16,7 @@ _f: # @f
Lfunc_begin0:
# BB#0: # %entry
.cv_file 1 "cv-empty-linetable.s"
+ .cv_func_id 1
.cv_loc 1 1 3 15 is_stmt 0
jmp _g # TAILCALL
Lfunc_end0:
diff --git a/llvm/test/MC/COFF/cv-errors.s b/llvm/test/MC/COFF/cv-errors.s
new file mode 100644
index 00000000000..ca2f77549c5
--- /dev/null
+++ b/llvm/test/MC/COFF/cv-errors.s
@@ -0,0 +1,56 @@
+# RUN: not llvm-mc %s -o /dev/null 2>&1 | FileCheck %s
+
+.text
+foo:
+.cv_file a
+# CHECK: error: expected file number in '.cv_file' directive
+# CHECK-NOT: error:
+.cv_file 0 "t.cpp"
+# CHECK: error: file number less than one
+# CHECK-NOT: error:
+.cv_func_id x
+# CHECK: error: expected function id in '.cv_func_id' directive
+# CHECK-NOT: error:
+.cv_func_id -1
+# CHECK: error: expected function id in '.cv_func_id' directive
+# CHECK-NOT: error:
+.cv_func_id 0xFFFFFFFFFFFFFFFF
+# CHECK: error: expected function id within range [0, UINT_MAX)
+# CHECK-NOT: error:
+.cv_inline_site_id x
+# CHECK: error: expected function id in '.cv_inline_site_id' directive
+# CHECK-NOT: error:
+
+.cv_file 1 "t.cpp"
+.cv_func_id 0
+
+.cv_inline_site_id 0 0 0 0 0 0
+# CHECK: error: expected 'within' identifier in '.cv_inline_site_id' directive
+# CHECK-NOT: error:
+
+.cv_inline_site_id 0 within a
+# CHECK: error: expected function id in '.cv_inline_site_id' directive
+# CHECK-NOT: error:
+
+.cv_inline_site_id 0 within 0 x
+# CHECK: error: expected 'inlined_at' identifier in '.cv_inline_site_id' directive
+# CHECK-NOT: error:
+
+.cv_inline_site_id 0 within 0 inlined_at 0 0 0
+# CHECK: error: file number less than one in '.cv_inline_site_id' directive
+# CHECK-NOT: error:
+
+.cv_inline_site_id 0 within 0 inlined_at 10 0 0
+# CHECK: error: unassigned file number in '.cv_inline_site_id' directive
+# CHECK-NOT: error:
+
+.cv_inline_site_id 0 within 0 inlined_at 1 1 1
+# CHECK: error: function id already allocated
+# CHECK-NOT: error:
+
+.cv_inline_site_id 1 within 0 inlined_at 1 1 1
+
+.cv_loc 0 1 1 1 # t.cpp:1:1
+nop
+.cv_loc 1 1 1 1 # t.cpp:1:1
+nop
diff --git a/llvm/test/MC/COFF/cv-inline-linetable-infloop.s b/llvm/test/MC/COFF/cv-inline-linetable-infloop.s
index cd0a073be2a..804ed6f404d 100644
--- a/llvm/test/MC/COFF/cv-inline-linetable-infloop.s
+++ b/llvm/test/MC/COFF/cv-inline-linetable-infloop.s
@@ -19,6 +19,8 @@
.p2align 4, 0x90
infloop: # @infloop
.Lfunc_begin1:
+ .cv_func_id 0
+ .cv_inline_site_id 2 within 0 inlined_at 1 1 1
.cv_loc 2 1 3 7 # t.c:3:7
jmp .Lfunc_begin1
.Lfunc_end1:
@@ -31,6 +33,7 @@ infloop: # @infloop
.globl afterinfloop
.p2align 4, 0x90
afterinfloop: # @afterinfloop
+ .cv_func_id 3
.cv_loc 3 1 13 0 # t.c:13:0
retq
diff --git a/llvm/test/MC/COFF/cv-inline-linetable-unlikely.s b/llvm/test/MC/COFF/cv-inline-linetable-unlikely.s
new file mode 100644
index 00000000000..dd3a66f419c
--- /dev/null
+++ b/llvm/test/MC/COFF/cv-inline-linetable-unlikely.s
@@ -0,0 +1,191 @@
+# RUN: llvm-mc -triple=x86_64-windows -filetype=obj < %s | llvm-readobj -codeview | FileCheck %s
+
+# C source to generate the assembly:
+# volatile int unlikely_cond = 0;
+# extern void __declspec(noreturn) abort();
+# __forceinline void f() {
+# if (unlikely_cond)
+# abort();
+# }
+# void g() {
+# unlikely_cond = 0;
+# f();
+# unlikely_cond = 0;
+# }
+
+# This test is interesting because the inlined instructions are discontiguous.
+# LLVM's block layout algorithms will put the 'abort' call last, as it is
+# considered highly unlikely to execute. This is similar to what it does for
+# calls to __asan_report*, for which it is very important to have an accurate
+# stack trace.
+
+# CHECK: ProcStart {
+# CHECK: FunctionType: g (0x1003)
+# CHECK: CodeOffset: g+0x0
+# CHECK: DisplayName: g
+# CHECK: LinkageName: g
+# CHECK: }
+# CHECK: InlineSite {
+# CHECK: Inlinee: f (0x1002)
+# CHECK: BinaryAnnotations [
+# CHECK-NEXT: ChangeCodeOffsetAndLineOffset: {CodeOffset: 0xE, LineOffset: 1}
+# CHECK-NEXT: ChangeCodeLength: 0x9
+# CHECK-NEXT: ChangeCodeOffsetAndLineOffset: {CodeOffset: 0xF, LineOffset: 1}
+# CHECK-NEXT: ChangeCodeLength: 0x7
+# CHECK-NEXT: ]
+
+ .text
+ .globl g
+g: # @g
+.Lfunc_begin0:
+ .cv_func_id 0
+ .cv_file 1 "C:\\src\\llvm\\build\\t.cpp"
+ .cv_loc 0 1 7 0 is_stmt 0 # t.cpp:7:0
+.seh_proc g
+ subq $40, %rsp
+ .seh_stackalloc 40
+ .seh_endprologue
+ .cv_loc 0 1 8 17 # t.cpp:8:17
+ movl $0, unlikely_cond(%rip)
+ .cv_inline_site_id 1 within 0 inlined_at 1 9 3
+ .cv_loc 1 1 4 7 # t.cpp:4:7
+ cmpl $0, unlikely_cond(%rip)
+ jne .LBB0_1
+ .cv_loc 0 1 10 17 # t.cpp:10:17
+ movl $0, unlikely_cond(%rip)
+ .cv_loc 0 1 11 1 # t.cpp:11:1
+ addq $40, %rsp
+ retq
+
+.LBB0_1: # %if.then.i
+ .cv_loc 1 1 5 5 # t.cpp:5:5
+ callq abort
+ ud2
+.Lfunc_end0:
+ .seh_handlerdata
+ .text
+ .seh_endproc
+
+ .bss
+ .globl unlikely_cond # @unlikely_cond
+ .p2align 2
+unlikely_cond:
+ .long 0 # 0x0
+
+ .section .debug$S,"dr"
+ .p2align 2
+ .long 4 # Debug section magic
+ .long 246 # Inlinee lines subsection
+ .long .Ltmp9-.Ltmp8 # Subsection size
+.Ltmp8:
+ .long 0 # Inlinee lines signature
+
+ # Inlined function f starts at t.cpp:3
+ .long 4098 # Type index of inlined function
+ .long 0 # Offset into filechecksum table
+ .long 3 # Starting line number
+.Ltmp9:
+ .p2align 2
+ .long 241 # Symbol subsection for g
+ .long .Ltmp11-.Ltmp10 # Subsection size
+.Ltmp10:
+ .short .Ltmp13-.Ltmp12 # Record length
+.Ltmp12:
+ .short 4423 # Record kind: S_GPROC32_ID
+ .long 0 # PtrParent
+ .long 0 # PtrEnd
+ .long 0 # PtrNext
+ .long .Lfunc_end0-g # Code size
+ .long 0 # Offset after prologue
+ .long 0 # Offset before epilogue
+ .long 4099 # Function type index
+ .secrel32 g # Function section relative address
+ .secidx g # Function section index
+ .byte 0 # Flags
+ .asciz "g" # Function name
+.Ltmp13:
+ .short .Ltmp15-.Ltmp14 # Record length
+.Ltmp14:
+ .short 4429 # Record kind: S_INLINESITE
+ .long 0 # PtrParent
+ .long 0 # PtrEnd
+ .long 4098 # Inlinee type index
+ .cv_inline_linetable 1 1 3 .Lfunc_begin0 .Lfunc_end0
+.Ltmp15:
+ .short 2 # Record length
+ .short 4430 # Record kind: S_INLINESITE_END
+ .short 2 # Record length
+ .short 4431 # Record kind: S_PROC_ID_END
+.Ltmp11:
+ .p2align 2
+ .cv_linetable 0, g, .Lfunc_end0
+ .long 241 # Symbol subsection for globals
+ .long .Ltmp17-.Ltmp16 # Subsection size
+.Ltmp16:
+ .short .Ltmp19-.Ltmp18 # Record length
+.Ltmp18:
+ .short 4365 # Record kind: S_GDATA32
+ .long 4100 # Type
+ .secrel32 unlikely_cond # DataOffset
+ .secidx unlikely_cond # Segment
+ .asciz "unlikely_cond" # Name
+.Ltmp19:
+.Ltmp17:
+ .p2align 2
+ .cv_filechecksums # File index to string table offset subsection
+ .cv_stringtable # String table
+ .section .debug$T,"dr"
+ .p2align 2
+ .long 4 # Debug section magic
+ # ArgList (0x1000) {
+ # TypeLeafKind: LF_ARGLIST (0x1201)
+ # NumArgs: 0
+ # Arguments [
+ # ]
+ # }
+ .byte 0x06, 0x00, 0x01, 0x12
+ .byte 0x00, 0x00, 0x00, 0x00
+ # Procedure (0x1001) {
+ # TypeLeafKind: LF_PROCEDURE (0x1008)
+ # ReturnType: void (0x3)
+ # CallingConvention: NearC (0x0)
+ # FunctionOptions [ (0x0)
+ # ]
+ # NumParameters: 0
+ # ArgListType: () (0x1000)
+ # }
+ .byte 0x0e, 0x00, 0x08, 0x10
+ .byte 0x03, 0x00, 0x00, 0x00
+ .byte 0x00, 0x00, 0x00, 0x00
+ .byte 0x00, 0x10, 0x00, 0x00
+ # FuncId (0x1002) {
+ # TypeLeafKind: LF_FUNC_ID (0x1601)
+ # ParentScope: 0x0
+ # FunctionType: void () (0x1001)
+ # Name: f
+ # }
+ .byte 0x0e, 0x00, 0x01, 0x16
+ .byte 0x00, 0x00, 0x00, 0x00
+ .byte 0x01, 0x10, 0x00, 0x00
+ .byte 0x66, 0x00, 0xf2, 0xf1
+ # FuncId (0x1003) {
+ # TypeLeafKind: LF_FUNC_ID (0x1601)
+ # ParentScope: 0x0
+ # FunctionType: void () (0x1001)
+ # Name: g
+ # }
+ .byte 0x0e, 0x00, 0x01, 0x16
+ .byte 0x00, 0x00, 0x00, 0x00
+ .byte 0x01, 0x10, 0x00, 0x00
+ .byte 0x67, 0x00, 0xf2, 0xf1
+ # Modifier (0x1004) {
+ # TypeLeafKind: LF_MODIFIER (0x1001)
+ # ModifiedType: int (0x74)
+ # Modifiers [ (0x2)
+ # Volatile (0x2)
+ # ]
+ # }
+ .byte 0x0a, 0x00, 0x01, 0x10
+ .byte 0x74, 0x00, 0x00, 0x00
+ .byte 0x02, 0x00, 0xf2, 0xf1
+
diff --git a/llvm/test/MC/COFF/cv-inline-linetable-unreachable.s b/llvm/test/MC/COFF/cv-inline-linetable-unreachable.s
index eb89dd51927..0f29d1667c3 100644
--- a/llvm/test/MC/COFF/cv-inline-linetable-unreachable.s
+++ b/llvm/test/MC/COFF/cv-inline-linetable-unreachable.s
@@ -15,6 +15,8 @@
_g: # @g
Lfunc_begin0:
.cv_file 1 "\\usr\\local\\google\\home\\majnemer\\llvm\\src\\<stdin>"
+ .cv_func_id 0
+ .cv_inline_site_id 1 within 0 inlined_at 1 1 1
.cv_loc 0 1 7 0 is_stmt 0 # <stdin>:7:0
# BB#0: # %entry
pushl %ebp
diff --git a/llvm/test/MC/COFF/cv-inline-linetable.s b/llvm/test/MC/COFF/cv-inline-linetable.s
index 67c6da2ab09..bb68fcde21b 100644
--- a/llvm/test/MC/COFF/cv-inline-linetable.s
+++ b/llvm/test/MC/COFF/cv-inline-linetable.s
@@ -15,6 +15,9 @@
"?baz@@YAXXZ": # @"\01?baz@@YAXXZ"
Lfunc_begin0:
.cv_file 1 "D:\\src\\llvm\\build\\t.cpp"
+ .cv_func_id 0
+ .cv_inline_site_id 1 within 0 inlined_at 1 15 3
+ .cv_inline_site_id 2 within 1 inlined_at 1 10 3
.cv_loc 0 1 13 0 is_stmt 0 # t.cpp:13:0
# BB#0: # %entry
pushl %eax
@@ -84,16 +87,18 @@ Ltmp3:
Ltmp4:
.short 4429
.asciz "\000\000\000\000\000\000\000\000\003\020\000"
- .cv_inline_linetable 1 1 9 Lfunc_begin0 Lfunc_end0 contains 2
+ .cv_inline_linetable 1 1 9 Lfunc_begin0 Lfunc_end0
# CHECK: InlineSite {
# CHECK: PtrParent: 0x0
# CHECK: PtrEnd: 0x0
# CHECK: Inlinee: bar (0x1003)
# CHECK: BinaryAnnotations [
-# CHECK: ChangeLineOffset: 2
-# CHECK: ChangeCodeOffset: 0x2D
-# CHECK: ChangeCodeLength: 0x7
-# CHECK: ]
+# CHECK-NEXT: ChangeCodeOffsetAndLineOffset: {CodeOffset: 0x8, LineOffset: 0}
+# CHECK-NEXT: ChangeCodeOffsetAndLineOffset: {CodeOffset: 0x7, LineOffset: 1}
+# CHECK-NEXT: ChangeLineOffset: 1
+# CHECK-NEXT: ChangeCodeOffset: 0x1E
+# CHECK-NEXT: ChangeCodeLength: 0x7
+# CHECK-NEXT: ]
# CHECK: }
Ltmp5:
.short Ltmp7-Ltmp6
@@ -106,12 +111,12 @@ Ltmp6:
# CHECK: PtrEnd: 0x0
# CHECK: Inlinee: foo (0x1004)
# CHECK: BinaryAnnotations [
-# CHECK: ChangeLineOffset: 1
-# CHECK: ChangeCodeOffset: 0x19
-# CHECK: ChangeCodeOffsetAndLineOffset: {CodeOffset: 0x6, LineOffset: 1}
-# CHECK: ChangeCodeOffsetAndLineOffset: {CodeOffset: 0x7, LineOffset: 1}
-# CHECK: ChangeCodeLength: 0x7
-# CHECK: ]
+# CHECK-NEXT: ChangeCodeOffsetAndLineOffset: {CodeOffset: 0xF, LineOffset: 0}
+# CHECK-NEXT: ChangeCodeOffsetAndLineOffset: {CodeOffset: 0xA, LineOffset: 1}
+# CHECK-NEXT: ChangeCodeOffsetAndLineOffset: {CodeOffset: 0x6, LineOffset: 1}
+# CHECK-NEXT: ChangeCodeOffsetAndLineOffset: {CodeOffset: 0x7, LineOffset: 1}
+# CHECK-NEXT: ChangeCodeLength: 0x7
+# CHECK-NEXT: ]
# CHECK: }
Ltmp7:
.short 2
diff --git a/llvm/test/MC/COFF/cv-loc-cross-section.s b/llvm/test/MC/COFF/cv-loc-cross-section.s
new file mode 100644
index 00000000000..357fe5b2565
--- /dev/null
+++ b/llvm/test/MC/COFF/cv-loc-cross-section.s
@@ -0,0 +1,26 @@
+# RUN: not llvm-mc < %s -o /dev/null 2>&1 | FileCheck %s
+
+ .text
+ .global baz
+baz:
+.Lfunc_begin0:
+ .cv_file 1 "t.cpp"
+ .cv_func_id 0
+ .cv_loc 0 1 1 1
+ pushq %rbp
+ movq %rsp, %rbp
+ .cv_loc 0 1 2 1
+
+ .data # Switching sections raises an error.
+
+ incl x(%rip)
+ .cv_loc 0 1 3 1
+# CHECK: error: all .cv_loc directives for a function must be in the same section
+ popq %rbp
+ retq
+.Lfunc_end0:
+
+ .section .debug$S,"dr"
+ .cv_linetable 0 .Lfunc_begin0 .Lfunc_end0
+ .short 2 # Record length
+ .short 2 # Record kind: S_INLINESITE_END
diff --git a/llvm/test/MC/COFF/cv-loc.s b/llvm/test/MC/COFF/cv-loc.s
index 08ab15aea44..01d5d02b224 100644
--- a/llvm/test/MC/COFF/cv-loc.s
+++ b/llvm/test/MC/COFF/cv-loc.s
@@ -7,6 +7,8 @@
.cv_file 1 "a.c"
.cv_file 2 "t.inc"
+.cv_func_id 0
+
# Implements this C:
# void f(volatile int *x) {
# ++*x;
OpenPOWER on IntegriCloud