[llvm] 87bbf3d - [XCOFF][DebugInfo] support DWARF for XCOFF for assembly output.
Chen Zheng via llvm-commits
llvm-commits at lists.llvm.org
Thu Mar 4 18:08:03 PST 2021
Author: Chen Zheng
Date: 2021-03-04T21:07:52-05:00
New Revision: 87bbf3d1f8c344c98a6f3079b76405ca22b83b79
URL: https://github.com/llvm/llvm-project/commit/87bbf3d1f8c344c98a6f3079b76405ca22b83b79
DIFF: https://github.com/llvm/llvm-project/commit/87bbf3d1f8c344c98a6f3079b76405ca22b83b79.diff
LOG: [XCOFF][DebugInfo] support DWARF for XCOFF for assembly output.
Reviewed By: jasonliu
Differential Revision: https://reviews.llvm.org/D95518
Added:
llvm/test/DebugInfo/XCOFF/empty.ll
llvm/test/DebugInfo/XCOFF/explicit-section.ll
llvm/test/DebugInfo/XCOFF/function-sections.ll
llvm/test/DebugInfo/XCOFF/lit.local.cfg
Modified:
llvm/include/llvm/MC/MCAsmInfo.h
llvm/include/llvm/MC/MCContext.h
llvm/include/llvm/MC/MCDwarf.h
llvm/include/llvm/MC/MCObjectStreamer.h
llvm/include/llvm/MC/MCSectionXCOFF.h
llvm/include/llvm/MC/MCStreamer.h
llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
llvm/lib/MC/MCAsmInfoXCOFF.cpp
llvm/lib/MC/MCAsmStreamer.cpp
llvm/lib/MC/MCContext.cpp
llvm/lib/MC/MCDwarf.cpp
llvm/lib/MC/MCObjectFileInfo.cpp
llvm/lib/MC/MCObjectStreamer.cpp
llvm/lib/MC/MCSectionXCOFF.cpp
llvm/lib/MC/MCStreamer.cpp
llvm/lib/MC/MCSymbolXCOFF.cpp
llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCAsmInfo.cpp
llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/MC/MCAsmInfo.h b/llvm/include/llvm/MC/MCAsmInfo.h
index 9b2ac558756e..309932b29bb1 100644
--- a/llvm/include/llvm/MC/MCAsmInfo.h
+++ b/llvm/include/llvm/MC/MCAsmInfo.h
@@ -388,6 +388,14 @@ class MCAsmInfo {
/// absolute
diff erence.
bool DwarfFDESymbolsUseAbsDiff = false;
+ /// True if the target supports generating the DWARF line table through using
+ /// the .loc/.file directives. Defaults to true.
+ bool UsesDwarfFileAndLocDirectives = true;
+
+ /// True if the target needs the DWARF section length in the header (if any)
+ /// of the DWARF section in the assembly file. Defaults to true.
+ bool DwarfSectionSizeRequired = true;
+
/// True if dwarf register numbers are printed instead of symbolic register
/// names in .cfi_* directives. Defaults to false.
bool DwarfRegNumForCFI = false;
@@ -673,6 +681,14 @@ class MCAsmInfo {
return SupportsExtendedDwarfLocDirective;
}
+ bool usesDwarfFileAndLocDirectives() const {
+ return UsesDwarfFileAndLocDirectives;
+ }
+
+ bool needsDwarfSectionSizeInHeader() const {
+ return DwarfSectionSizeRequired;
+ }
+
void addInitialFrameState(const MCCFIInstruction &Inst);
const std::vector<MCCFIInstruction> &getInitialFrameState() const {
diff --git a/llvm/include/llvm/MC/MCContext.h b/llvm/include/llvm/MC/MCContext.h
index 33874e83ead7..106763c5d7c2 100644
--- a/llvm/include/llvm/MC/MCContext.h
+++ b/llvm/include/llvm/MC/MCContext.h
@@ -279,16 +279,35 @@ namespace llvm {
};
struct XCOFFSectionKey {
+ // Section name.
std::string SectionName;
- XCOFF::StorageMappingClass MappingClass;
+ // Section property.
+ // For csect section, it is storage mapping class.
+ // For debug section, it is section type flags.
+ union {
+ XCOFF::StorageMappingClass MappingClass;
+ XCOFF::DwarfSectionSubtypeFlags DwarfSubtypeFlags;
+ };
+ bool IsCsect;
XCOFFSectionKey(StringRef SectionName,
XCOFF::StorageMappingClass MappingClass)
- : SectionName(SectionName), MappingClass(MappingClass) {}
+ : SectionName(SectionName), MappingClass(MappingClass),
+ IsCsect(true) {}
+
+ XCOFFSectionKey(StringRef SectionName,
+ XCOFF::DwarfSectionSubtypeFlags DwarfSubtypeFlags)
+ : SectionName(SectionName), DwarfSubtypeFlags(DwarfSubtypeFlags),
+ IsCsect(false) {}
bool operator<(const XCOFFSectionKey &Other) const {
- return std::tie(SectionName, MappingClass) <
- std::tie(Other.SectionName, Other.MappingClass);
+ if (IsCsect && Other.IsCsect)
+ return std::tie(SectionName, MappingClass) <
+ std::tie(Other.SectionName, Other.MappingClass);
+ if (IsCsect != Other.IsCsect)
+ return IsCsect;
+ return std::tie(SectionName, DwarfSubtypeFlags) <
+ std::tie(Other.SectionName, Other.DwarfSubtypeFlags);
}
};
@@ -599,11 +618,11 @@ namespace llvm {
const MCSymbolWasm *Group, unsigned UniqueID,
const char *BeginSymName);
- MCSectionXCOFF *
- getXCOFFSection(StringRef Section, SectionKind K,
- Optional<XCOFF::CsectProperties> CsectProp = None,
- bool MultiSymbolsAllowed = false,
- const char *BeginSymName = nullptr);
+ MCSectionXCOFF *getXCOFFSection(
+ StringRef Section, SectionKind K,
+ Optional<XCOFF::CsectProperties> CsectProp = None,
+ bool MultiSymbolsAllowed = false, const char *BeginSymName = nullptr,
+ Optional<XCOFF::DwarfSectionSubtypeFlags> DwarfSubtypeFlags = None);
// Create and save a copy of STI and return a reference to the copy.
MCSubtargetInfo &getSubtargetCopy(const MCSubtargetInfo &STI);
diff --git a/llvm/include/llvm/MC/MCDwarf.h b/llvm/include/llvm/MC/MCDwarf.h
index 5bf6496806d8..625e83a37da9 100644
--- a/llvm/include/llvm/MC/MCDwarf.h
+++ b/llvm/include/llvm/MC/MCDwarf.h
@@ -173,7 +173,7 @@ class MCDwarfLineEntry : public MCDwarfLoc {
// This is called when an instruction is assembled into the specified
// section and if there is information from the last .loc directive that
// has yet to have a line entry made for it is made.
- static void Make(MCObjectStreamer *MCOS, MCSection *Section);
+ static void make(MCStreamer *MCOS, MCSection *Section);
};
/// Instances of this class represent the line information for a compile
@@ -311,10 +311,10 @@ class MCDwarfLineTable {
public:
// This emits the Dwarf file and the line tables for all Compile Units.
- static void Emit(MCObjectStreamer *MCOS, MCDwarfLineTableParams Params);
+ static void emit(MCStreamer *MCOS, MCDwarfLineTableParams Params);
// This emits the Dwarf file and the line tables for a given Compile Unit.
- void EmitCU(MCObjectStreamer *MCOS, MCDwarfLineTableParams Params,
+ void emitCU(MCStreamer *MCOS, MCDwarfLineTableParams Params,
Optional<MCDwarfLineStr> &LineStr) const;
Expected<unsigned> tryGetFile(StringRef &Directory, StringRef &FileName,
diff --git a/llvm/include/llvm/MC/MCObjectStreamer.h b/llvm/include/llvm/MC/MCObjectStreamer.h
index a00000bc11b6..a0169c4c8228 100644
--- a/llvm/include/llvm/MC/MCObjectStreamer.h
+++ b/llvm/include/llvm/MC/MCObjectStreamer.h
@@ -146,7 +146,9 @@ class MCObjectStreamer : public MCStreamer {
unsigned Discriminator,
StringRef FileName) override;
void emitDwarfAdvanceLineAddr(int64_t LineDelta, const MCSymbol *LastLabel,
- const MCSymbol *Label, unsigned PointerSize);
+ const MCSymbol *Label,
+ unsigned PointerSize) override;
+ void emitDwarfLineEndEntry(MCSection *Section, MCSymbol *LastLabel) override;
void emitDwarfAdvanceFrameAddr(const MCSymbol *LastLabel,
const MCSymbol *Label);
void emitCVLocDirective(unsigned FunctionId, unsigned FileNo, unsigned Line,
diff --git a/llvm/include/llvm/MC/MCSectionXCOFF.h b/llvm/include/llvm/MC/MCSectionXCOFF.h
index 768e398525bc..27c06a2c0877 100644
--- a/llvm/include/llvm/MC/MCSectionXCOFF.h
+++ b/llvm/include/llvm/MC/MCSectionXCOFF.h
@@ -35,6 +35,7 @@ class MCSectionXCOFF final : public MCSection {
Optional<XCOFF::CsectProperties> CsectProp;
MCSymbolXCOFF *const QualName;
StringRef SymbolTableName;
+ Optional<XCOFF::DwarfSectionSubtypeFlags> DwarfSubtypeFlags;
bool MultiSymbolsAllowed;
static constexpr unsigned DefaultAlignVal = 4;
@@ -44,12 +45,13 @@ class MCSectionXCOFF final : public MCSection {
bool MultiSymbolsAllowed)
: MCSection(SV_XCOFF, Name, K, Begin),
CsectProp(XCOFF::CsectProperties(SMC, ST)), QualName(QualName),
- SymbolTableName(SymbolTableName),
+ SymbolTableName(SymbolTableName), DwarfSubtypeFlags(None),
MultiSymbolsAllowed(MultiSymbolsAllowed) {
assert(
(ST == XCOFF::XTY_SD || ST == XCOFF::XTY_CM || ST == XCOFF::XTY_ER) &&
"Invalid or unhandled type for csect.");
assert(QualName != nullptr && "QualName is needed.");
+
QualName->setRepresentedCsect(this);
QualName->setStorageClass(XCOFF::C_HIDEXT);
// A csect is 4 byte aligned by default, except for undefined symbol csects.
@@ -58,10 +60,11 @@ class MCSectionXCOFF final : public MCSection {
}
MCSectionXCOFF(StringRef Name, SectionKind K, MCSymbolXCOFF *QualName,
+ XCOFF::DwarfSectionSubtypeFlags DwarfSubtypeFlags,
MCSymbol *Begin, StringRef SymbolTableName,
bool MultiSymbolsAllowed)
: MCSection(SV_XCOFF, Name, K, Begin), QualName(QualName),
- SymbolTableName(SymbolTableName),
+ SymbolTableName(SymbolTableName), DwarfSubtypeFlags(DwarfSubtypeFlags),
MultiSymbolsAllowed(MultiSymbolsAllowed) {
assert(QualName != nullptr && "QualName is needed.");
@@ -103,6 +106,10 @@ class MCSectionXCOFF final : public MCSection {
StringRef getSymbolTableName() const { return SymbolTableName; }
bool isMultiSymbolsAllowed() const { return MultiSymbolsAllowed; }
bool isCsect() const { return CsectProp.hasValue(); }
+ bool isDwarfSect() const { return DwarfSubtypeFlags.hasValue(); }
+ Optional<XCOFF::DwarfSectionSubtypeFlags> getDwarfSubtypeFlags() const {
+ return DwarfSubtypeFlags;
+ }
};
} // end namespace llvm
diff --git a/llvm/include/llvm/MC/MCStreamer.h b/llvm/include/llvm/MC/MCStreamer.h
index 7f50995fbdae..4156d69c4c02 100644
--- a/llvm/include/llvm/MC/MCStreamer.h
+++ b/llvm/include/llvm/MC/MCStreamer.h
@@ -1092,6 +1092,23 @@ class MCStreamer {
/// Return the end symbol generated inside, the caller needs to emit it.
virtual MCSymbol *emitDwarfUnitLength(const Twine &Prefix,
const Twine &Comment);
+
+ /// Emit the debug line start label.
+ virtual void emitDwarfLineStartLabel(MCSymbol *StartSym);
+
+ /// Emit the debug line end entry.
+ virtual void emitDwarfLineEndEntry(MCSection *Section, MCSymbol *LastLabel) {}
+
+ /// If targets does not support representing debug line section by .loc/.file
+ /// directives in assembly output, we need to populate debug line section with
+ /// raw debug line contents.
+ virtual void emitDwarfAdvanceLineAddr(int64_t LineDelta,
+ const MCSymbol *LastLabel,
+ const MCSymbol *Label,
+ unsigned PointerSize) {}
+
+ /// Do finalization for the streamer at the end of a section.
+ virtual void doFinalizationAtSectionEnd(MCSection *Section) {}
};
/// Create a dummy machine code streamer, which does nothing. This is useful for
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
index 438492e9f190..beed2a5126c4 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
@@ -392,11 +392,21 @@ DwarfDebug::DwarfDebug(AsmPrinter *A)
DwarfVersion =
TT.isNVPTX() ? 2 : (DwarfVersion ? DwarfVersion : dwarf::DWARF_VERSION);
- bool Dwarf64 =
- (Asm->TM.Options.MCOptions.Dwarf64 || MMI->getModule()->isDwarf64()) &&
- DwarfVersion >= 3 && // DWARF64 was introduced in DWARFv3.
- TT.isArch64Bit() && // DWARF64 requires 64-bit relocations.
- TT.isOSBinFormatELF(); // Support only ELF for now.
+ bool Dwarf64 = DwarfVersion >= 3 && // DWARF64 was introduced in DWARFv3.
+ TT.isArch64Bit(); // DWARF64 requires 64-bit relocations.
+
+ // Support DWARF64
+ // 1: For ELF when requested.
+ // 2: For XCOFF64: the AIX assembler will fill in debug section lengths
+ // according to the DWARF64 format for 64-bit assembly, so we must use
+ // DWARF64 in the compiler too for 64-bit mode.
+ Dwarf64 &=
+ ((Asm->TM.Options.MCOptions.Dwarf64 || MMI->getModule()->isDwarf64()) &&
+ TT.isOSBinFormatELF()) ||
+ TT.isOSBinFormatXCOFF();
+
+ if (!Dwarf64 && TT.isArch64Bit() && TT.isOSBinFormatXCOFF())
+ report_fatal_error("XCOFF requires DWARF64 for 64-bit mode!");
UseRangesSection = !NoDwarfRangesSection && !TT.isNVPTX();
diff --git a/llvm/lib/MC/MCAsmInfoXCOFF.cpp b/llvm/lib/MC/MCAsmInfoXCOFF.cpp
index 2f8bc6a49bb7..a23a71b865b4 100644
--- a/llvm/lib/MC/MCAsmInfoXCOFF.cpp
+++ b/llvm/lib/MC/MCAsmInfoXCOFF.cpp
@@ -23,6 +23,8 @@ MCAsmInfoXCOFF::MCAsmInfoXCOFF() {
PrivateLabelPrefix = "L..";
SupportsQuotedNames = false;
UseDotAlignForAlignment = true;
+ UsesDwarfFileAndLocDirectives = false;
+ DwarfSectionSizeRequired = false;
if (UseLEB128Directives == cl::BOU_UNSET)
HasLEB128Directives = false;
ZeroDirective = "\t.space\t";
diff --git a/llvm/lib/MC/MCAsmStreamer.cpp b/llvm/lib/MC/MCAsmStreamer.cpp
index 10d72553fe6d..e82ad28da64e 100644
--- a/llvm/lib/MC/MCAsmStreamer.cpp
+++ b/llvm/lib/MC/MCAsmStreamer.cpp
@@ -372,6 +372,21 @@ class MCAsmStreamer final : public MCStreamer {
void emitRawTextImpl(StringRef String) override;
void finishImpl() override;
+
+ void emitDwarfUnitLength(uint64_t Length, const Twine &Comment) override;
+
+ MCSymbol *emitDwarfUnitLength(const Twine &Prefix,
+ const Twine &Comment) override;
+
+ void emitDwarfLineStartLabel(MCSymbol *StartSym) override;
+
+ void emitDwarfLineEndEntry(MCSection *Section, MCSymbol *LastLabel) override;
+
+ void emitDwarfAdvanceLineAddr(int64_t LineDelta, const MCSymbol *LastLabel,
+ const MCSymbol *Label,
+ unsigned PointerSize) override;
+
+ void doFinalizationAtSectionEnd(MCSection *Section) override;
};
} // end anonymous namespace.
@@ -1419,7 +1434,11 @@ Expected<unsigned> MCAsmStreamer::tryEmitDwarfFileDirective(
if (!FileNoOrErr)
return FileNoOrErr.takeError();
FileNo = FileNoOrErr.get();
- if (NumFiles == Table.getMCDwarfFiles().size())
+
+ // Return early if this file is already emitted before or if target doesn't
+ // support .file directive.
+ if (NumFiles == Table.getMCDwarfFiles().size() ||
+ !MAI->usesDwarfFileAndLocDirectives())
return FileNo;
SmallString<128> Str;
@@ -1448,6 +1467,10 @@ void MCAsmStreamer::emitDwarfFile0Directive(StringRef Directory,
getContext().setMCLineTableRootFile(CUID, Directory, Filename, Checksum,
Source);
+ // Target doesn't support .loc/.file directives, return early.
+ if (!MAI->usesDwarfFileAndLocDirectives())
+ return;
+
SmallString<128> Str;
raw_svector_ostream OS1(Str);
printDwarfFileDirective(0, Directory, Filename, Checksum, Source,
@@ -1463,6 +1486,17 @@ void MCAsmStreamer::emitDwarfLocDirective(unsigned FileNo, unsigned Line,
unsigned Column, unsigned Flags,
unsigned Isa, unsigned Discriminator,
StringRef FileName) {
+ // If target doesn't support .loc/.file directive, we need to record the lines
+ // same way like we do in object mode.
+ if (!MAI->usesDwarfFileAndLocDirectives()) {
+ // In case we see two .loc directives in a row, make sure the
+ // first one gets a line entry.
+ MCDwarfLineEntry::make(this, getCurrentSectionOnly());
+ this->MCStreamer::emitDwarfLocDirective(FileNo, Line, Column, Flags, Isa,
+ Discriminator, FileName);
+ return;
+ }
+
OS << "\t.loc\t" << FileNo << " " << Line << " " << Column;
if (MAI->supportsExtendedDwarfLocDirective()) {
if (Flags & DWARF2_FLAG_BASIC_BLOCK)
@@ -2106,6 +2140,11 @@ void MCAsmStreamer::emitInstruction(const MCInst &Inst,
assert(getCurrentSectionOnly() &&
"Cannot emit contents before setting section!");
+ if (!MAI->usesDwarfFileAndLocDirectives())
+ // Now that a machine instruction has been assembled into this section, make
+ // a line entry for any .loc directive that has been seen.
+ MCDwarfLineEntry::make(this, getCurrentSectionOnly());
+
// Show the encoding in a comment if we have a code emitter.
AddEncodingComment(Inst, STI);
@@ -2197,6 +2236,13 @@ void MCAsmStreamer::finishImpl() {
if (getContext().getGenDwarfForAssembly())
MCGenDwarfInfo::Emit(this);
+ // Now it is time to emit debug line sections if target doesn't support .loc
+ // and .line directives.
+ if (!MAI->usesDwarfFileAndLocDirectives()) {
+ MCDwarfLineTable::emit(this, getAssembler().getDWARFLinetableParams());
+ return;
+ }
+
// Emit the label for the line table, if requested - since the rest of the
// line table will be defined by .loc/.file directives, and not emitted
// directly, the label is the only work required here.
@@ -2210,6 +2256,135 @@ void MCAsmStreamer::finishImpl() {
}
}
+void MCAsmStreamer::emitDwarfUnitLength(uint64_t Length, const Twine &Comment) {
+ // If the assembler on some target fills in the DWARF unit length, we
+ // don't want to emit the length in the compiler. For example, the AIX
+ // assembler requires the assembly file with the unit length omitted from
+ // the debug section headers. In such cases, any label we placed occurs
+ // after the implied length field. We need to adjust the reference here
+ // to account for the offset introduced by the inserted length field.
+ if (!MAI->needsDwarfSectionSizeInHeader())
+ return;
+ MCStreamer::emitDwarfUnitLength(Length, Comment);
+}
+
+MCSymbol *MCAsmStreamer::emitDwarfUnitLength(const Twine &Prefix,
+ const Twine &Comment) {
+ // If the assembler on some target fills in the DWARF unit length, we
+ // don't want to emit the length in the compiler. For example, the AIX
+ // assembler requires the assembly file with the unit length omitted from
+ // the debug section headers. In such cases, any label we placed occurs
+ // after the implied length field. We need to adjust the reference here
+ // to account for the offset introduced by the inserted length field.
+ if (!MAI->needsDwarfSectionSizeInHeader())
+ return getContext().createTempSymbol(Prefix + "_end");
+ return MCStreamer::emitDwarfUnitLength(Prefix, Comment);
+}
+
+void MCAsmStreamer::emitDwarfLineStartLabel(MCSymbol *StartSym) {
+ // If the assembler on some target fills in the DWARF unit length, we
+ // don't want to emit the length in the compiler. For example, the AIX
+ // assembler requires the assembly file with the unit length omitted from
+ // the debug section headers. In such cases, any label we placed occurs
+ // after the implied length field. We need to adjust the reference here
+ // to account for the offset introduced by the inserted length field.
+ MCContext &Ctx = getContext();
+ if (!MAI->needsDwarfSectionSizeInHeader()) {
+ MCSymbol *DebugLineSymTmp = Ctx.createTempSymbol("debug_line_");
+ // Emit the symbol which does not contain the unit length field.
+ emitLabel(DebugLineSymTmp);
+
+ // Adjust the outer reference to account for the offset introduced by the
+ // inserted length field.
+ unsigned LengthFieldSize =
+ dwarf::getUnitLengthFieldByteSize(Ctx.getDwarfFormat());
+ const MCExpr *EntrySize = MCConstantExpr::create(LengthFieldSize, Ctx);
+ const MCExpr *OuterSym = MCBinaryExpr::createSub(
+ MCSymbolRefExpr::create(DebugLineSymTmp, Ctx), EntrySize, Ctx);
+
+ emitAssignment(StartSym, OuterSym);
+ return;
+ }
+ MCStreamer::emitDwarfLineStartLabel(StartSym);
+}
+
+void MCAsmStreamer::emitDwarfLineEndEntry(MCSection *Section,
+ MCSymbol *LastLabel) {
+ // If the targets write the raw debug line data for assembly output (We can
+ // not switch to Section and add the end symbol there for assembly output)
+ // we currently use the .text end label as any section end. This will not
+ // impact the debugability as we will jump to the caller of the last function
+ // in the section before we come into the .text end address.
+ assert(!MAI->usesDwarfFileAndLocDirectives() &&
+ ".loc should not be generated together with raw data!");
+
+ MCContext &Ctx = getContext();
+
+ // FIXME: use section end symbol as end of the Section. We need to consider
+ // the explicit sections and -ffunction-sections when we try to generate or
+ // find section end symbol for the Section.
+ MCSection *TextSection = Ctx.getObjectFileInfo()->getTextSection();
+ assert(TextSection->hasEnded() && ".text section is not end!");
+
+ MCSymbol *SectionEnd = TextSection->getEndSymbol(Ctx);
+ const MCAsmInfo *AsmInfo = Ctx.getAsmInfo();
+ emitDwarfAdvanceLineAddr(INT64_MAX, LastLabel, SectionEnd,
+ AsmInfo->getCodePointerSize());
+}
+
+// Generate DWARF line sections for assembly mode without .loc/.file
+void MCAsmStreamer::emitDwarfAdvanceLineAddr(int64_t LineDelta,
+ const MCSymbol *LastLabel,
+ const MCSymbol *Label,
+ unsigned PointerSize) {
+ assert(!MAI->usesDwarfFileAndLocDirectives() &&
+ ".loc/.file don't need raw data in debug line section!");
+
+ // Set to new address.
+ AddComment("Set address to " + Label->getName());
+ emitIntValue(dwarf::DW_LNS_extended_op, 1);
+ emitULEB128IntValue(PointerSize + 1);
+ emitIntValue(dwarf::DW_LNE_set_address, 1);
+ emitSymbolValue(Label, PointerSize);
+
+ if (!LastLabel) {
+ // Emit the sequence for the LineDelta (from 1) and a zero address delta.
+ AddComment("Start sequence");
+ MCDwarfLineAddr::Emit(this, MCDwarfLineTableParams(), LineDelta, 0);
+ return;
+ }
+
+ // INT64_MAX is a signal of the end of the section. Emit DW_LNE_end_sequence
+ // for the end of the section.
+ if (LineDelta == INT64_MAX) {
+ AddComment("End sequence");
+ emitIntValue(dwarf::DW_LNS_extended_op, 1);
+ emitULEB128IntValue(1);
+ emitIntValue(dwarf::DW_LNE_end_sequence, 1);
+ return;
+ }
+
+ // Advance line.
+ AddComment("Advance line " + Twine(LineDelta));
+ emitIntValue(dwarf::DW_LNS_advance_line, 1);
+ emitSLEB128IntValue(LineDelta);
+ emitIntValue(dwarf::DW_LNS_copy, 1);
+}
+
+void MCAsmStreamer::doFinalizationAtSectionEnd(MCSection *Section) {
+ // Emit section end. This is used to tell the debug line section where the end
+ // is for a text section if we don't use .loc to represent the debug line.
+ if (MAI->usesDwarfFileAndLocDirectives())
+ return;
+
+ SwitchSectionNoChange(Section);
+
+ MCSymbol *Sym = getCurrentSectionOnly()->getEndSymbol(getContext());
+
+ if (!Sym->isInSection())
+ emitLabel(Sym);
+}
+
MCStreamer *llvm::createAsmStreamer(MCContext &Context,
std::unique_ptr<formatted_raw_ostream> OS,
bool isVerboseAsm, bool useDwarfDirectory,
diff --git a/llvm/lib/MC/MCContext.cpp b/llvm/lib/MC/MCContext.cpp
index b0eb47069d7e..cf7e38f09493 100644
--- a/llvm/lib/MC/MCContext.cpp
+++ b/llvm/lib/MC/MCContext.cpp
@@ -686,15 +686,20 @@ MCSectionWasm *MCContext::getWasmSection(const Twine &Section, SectionKind Kind,
return Result;
}
-MCSectionXCOFF *
-MCContext::getXCOFFSection(StringRef Section, SectionKind Kind,
- Optional<XCOFF::CsectProperties> CsectProp,
- bool MultiSymbolsAllowed, const char *BeginSymName) {
+MCSectionXCOFF *MCContext::getXCOFFSection(
+ StringRef Section, SectionKind Kind,
+ Optional<XCOFF::CsectProperties> CsectProp, bool MultiSymbolsAllowed,
+ const char *BeginSymName,
+ Optional<XCOFF::DwarfSectionSubtypeFlags> DwarfSectionSubtypeFlags) {
+ bool IsDwarfSec = DwarfSectionSubtypeFlags.hasValue();
+ assert((IsDwarfSec != CsectProp.hasValue()) && "Invalid XCOFF section!");
+
// Do the lookup. If we have a hit, return it.
- // FIXME: handle the case for non-csect sections. Non-csect section has None
- // CsectProp.
auto IterBool = XCOFFUniquingMap.insert(std::make_pair(
- XCOFFSectionKey{Section.str(), CsectProp->MappingClass}, nullptr));
+ IsDwarfSec
+ ? XCOFFSectionKey(Section.str(), DwarfSectionSubtypeFlags.getValue())
+ : XCOFFSectionKey(Section.str(), CsectProp->MappingClass),
+ nullptr));
auto &Entry = *IterBool.first;
if (!IterBool.second) {
MCSectionXCOFF *ExistedEntry = Entry.second;
@@ -706,9 +711,14 @@ MCContext::getXCOFFSection(StringRef Section, SectionKind Kind,
// Otherwise, return a new section.
StringRef CachedName = Entry.first.SectionName;
- MCSymbolXCOFF *QualName = cast<MCSymbolXCOFF>(getOrCreateSymbol(
- CachedName + "[" + XCOFF::getMappingClassString(CsectProp->MappingClass) +
- "]"));
+ MCSymbolXCOFF *QualName = nullptr;
+ // Debug section don't have storage class attribute.
+ if (IsDwarfSec)
+ QualName = cast<MCSymbolXCOFF>(getOrCreateSymbol(CachedName));
+ else
+ QualName = cast<MCSymbolXCOFF>(getOrCreateSymbol(
+ CachedName + "[" +
+ XCOFF::getMappingClassString(CsectProp->MappingClass) + "]"));
MCSymbol *Begin = nullptr;
if (BeginSymName)
@@ -716,9 +726,18 @@ MCContext::getXCOFFSection(StringRef Section, SectionKind Kind,
// QualName->getUnqualifiedName() and CachedName are the same except when
// CachedName contains invalid character(s) such as '$' for an XCOFF symbol.
- MCSectionXCOFF *Result = new (XCOFFAllocator.Allocate()) MCSectionXCOFF(
- QualName->getUnqualifiedName(), CsectProp->MappingClass, CsectProp->Type,
- Kind, QualName, Begin, CachedName, MultiSymbolsAllowed);
+ MCSectionXCOFF *Result = nullptr;
+ if (IsDwarfSec)
+ Result = new (XCOFFAllocator.Allocate())
+ MCSectionXCOFF(QualName->getUnqualifiedName(), Kind, QualName,
+ DwarfSectionSubtypeFlags.getValue(), Begin, CachedName,
+ MultiSymbolsAllowed);
+ else
+ Result = new (XCOFFAllocator.Allocate())
+ MCSectionXCOFF(QualName->getUnqualifiedName(), CsectProp->MappingClass,
+ CsectProp->Type, Kind, QualName, Begin, CachedName,
+ MultiSymbolsAllowed);
+
Entry.second = Result;
auto *F = new MCDataFragment();
diff --git a/llvm/lib/MC/MCDwarf.cpp b/llvm/lib/MC/MCDwarf.cpp
index df04f113741d..6c23d330e0ea 100644
--- a/llvm/lib/MC/MCDwarf.cpp
+++ b/llvm/lib/MC/MCDwarf.cpp
@@ -105,7 +105,7 @@ static inline uint64_t ScaleAddrDelta(MCContext &Context, uint64_t AddrDelta) {
// and if there is information from the last .loc directive that has yet to have
// a line entry made for it is made.
//
-void MCDwarfLineEntry::Make(MCObjectStreamer *MCOS, MCSection *Section) {
+void MCDwarfLineEntry::make(MCStreamer *MCOS, MCSection *Section) {
if (!MCOS->getContext().getDwarfLocSeen())
return;
@@ -163,7 +163,7 @@ makeStartPlusIntExpr(MCContext &Ctx, const MCSymbol &Start, int IntVal) {
// in the LineSection.
//
static inline void emitDwarfLineTable(
- MCObjectStreamer *MCOS, MCSection *Section,
+ MCStreamer *MCOS, MCSection *Section,
const MCLineSection::MCDwarfLineEntryCollection &LineEntries) {
unsigned FileNum = 1;
unsigned LastLine = 1;
@@ -226,27 +226,14 @@ static inline void emitDwarfLineTable(
LastLabel = Label;
}
- // Emit a DW_LNE_end_sequence for the end of the section.
- // Use the section end label to compute the address delta and use INT64_MAX
- // as the line delta which is the signal that this is actually a
- // DW_LNE_end_sequence.
- MCSymbol *SectionEnd = MCOS->endSection(Section);
-
- // Switch back the dwarf line section, in case endSection had to switch the
- // section.
- MCContext &Ctx = MCOS->getContext();
- MCOS->SwitchSection(Ctx.getObjectFileInfo()->getDwarfLineSection());
-
- const MCAsmInfo *AsmInfo = Ctx.getAsmInfo();
- MCOS->emitDwarfAdvanceLineAddr(INT64_MAX, LastLabel, SectionEnd,
- AsmInfo->getCodePointerSize());
+ // Generate DWARF line end entry.
+ MCOS->emitDwarfLineEndEntry(Section, LastLabel);
}
//
// This emits the Dwarf file and the line tables.
//
-void MCDwarfLineTable::Emit(MCObjectStreamer *MCOS,
- MCDwarfLineTableParams Params) {
+void MCDwarfLineTable::emit(MCStreamer *MCOS, MCDwarfLineTableParams Params) {
MCContext &context = MCOS->getContext();
auto &LineTables = context.getMCDwarfLineTables();
@@ -266,7 +253,7 @@ void MCDwarfLineTable::Emit(MCObjectStreamer *MCOS,
// Handle the rest of the Compile Units.
for (const auto &CUIDTablePair : LineTables) {
- CUIDTablePair.second.EmitCU(MCOS, Params, LineStr);
+ CUIDTablePair.second.emitCU(MCOS, Params, LineStr);
}
if (LineStr)
@@ -471,8 +458,9 @@ MCDwarfLineTableHeader::Emit(MCStreamer *MCOS, MCDwarfLineTableParams Params,
MCSymbol *LineStartSym = Label;
if (!LineStartSym)
LineStartSym = context.createTempSymbol();
+
// Set the value of the symbol, as we are at the start of the line table.
- MCOS->emitLabel(LineStartSym);
+ MCOS->emitDwarfLineStartLabel(LineStartSym);
unsigned OffsetSize = dwarf::getDwarfOffsetByteSize(context.getDwarfFormat());
@@ -529,8 +517,7 @@ MCDwarfLineTableHeader::Emit(MCStreamer *MCOS, MCDwarfLineTableParams Params,
return std::make_pair(LineStartSym, LineEndSym);
}
-void MCDwarfLineTable::EmitCU(MCObjectStreamer *MCOS,
- MCDwarfLineTableParams Params,
+void MCDwarfLineTable::emitCU(MCStreamer *MCOS, MCDwarfLineTableParams Params,
Optional<MCDwarfLineStr> &LineStr) const {
MCSymbol *LineEndSym = Header.Emit(MCOS, Params, LineStr).second;
diff --git a/llvm/lib/MC/MCObjectFileInfo.cpp b/llvm/lib/MC/MCObjectFileInfo.cpp
index 06c1ae6b0717..155104cddda2 100644
--- a/llvm/lib/MC/MCObjectFileInfo.cpp
+++ b/llvm/lib/MC/MCObjectFileInfo.cpp
@@ -914,18 +914,49 @@ void MCObjectFileInfo::initXCOFFMCObjectFileInfo(const Triple &T) {
// DWARF sections for XCOFF are not csects. They are special STYP_DWARF
// sections, and the individual DWARF sections are distinguished by their
// section subtype.
- // TODO: Populate the DWARF sections appropriately.
- DwarfAbbrevSection = nullptr; // SSUBTYP_DWABREV
- DwarfInfoSection = nullptr; // SSUBTYP_DWINFO
- DwarfLineSection = nullptr; // SSUBTYP_DWLINE
- DwarfFrameSection = nullptr; // SSUBTYP_DWFRAME
- DwarfPubNamesSection = nullptr; // SSUBTYP_DWPBNMS
- DwarfPubTypesSection = nullptr; // SSUBTYP_DWPBTYP
- DwarfStrSection = nullptr; // SSUBTYP_DWSTR
- DwarfLocSection = nullptr; // SSUBTYP_DWLOC
- DwarfARangesSection = nullptr; // SSUBTYP_DWARNGE
- DwarfRangesSection = nullptr; // SSUBTYP_DWRNGES
- DwarfMacinfoSection = nullptr; // SSUBTYP_DWMAC
+ DwarfAbbrevSection = Ctx->getXCOFFSection(
+ ".dwabrev", SectionKind::getMetadata(), /* CsectProperties */ None,
+ /* MultiSymbolsAllowed */ true, ".dwabrev", XCOFF::SSUBTYP_DWABREV);
+
+ DwarfInfoSection = Ctx->getXCOFFSection(
+ ".dwinfo", SectionKind::getMetadata(), /* CsectProperties */ None,
+ /* MultiSymbolsAllowed */ true, ".dwinfo", XCOFF::SSUBTYP_DWINFO);
+
+ DwarfLineSection = Ctx->getXCOFFSection(
+ ".dwline", SectionKind::getMetadata(), /* CsectProperties */ None,
+ /* MultiSymbolsAllowed */ true, ".dwline", XCOFF::SSUBTYP_DWLINE);
+
+ DwarfFrameSection = Ctx->getXCOFFSection(
+ ".dwframe", SectionKind::getMetadata(), /* CsectProperties */ None,
+ /* MultiSymbolsAllowed */ true, ".dwframe", XCOFF::SSUBTYP_DWFRAME);
+
+ DwarfPubNamesSection = Ctx->getXCOFFSection(
+ ".dwpbnms", SectionKind::getMetadata(), /* CsectProperties */ None,
+ /* MultiSymbolsAllowed */ true, ".dwpbnms", XCOFF::SSUBTYP_DWPBNMS);
+
+ DwarfPubTypesSection = Ctx->getXCOFFSection(
+ ".dwpbtyp", SectionKind::getMetadata(), /* CsectProperties */ None,
+ /* MultiSymbolsAllowed */ true, ".dwpbtyp", XCOFF::SSUBTYP_DWPBTYP);
+
+ DwarfStrSection = Ctx->getXCOFFSection(
+ ".dwstr", SectionKind::getMetadata(), /* CsectProperties */ None,
+ /* MultiSymbolsAllowed */ true, ".dwstr", XCOFF::SSUBTYP_DWSTR);
+
+ DwarfLocSection = Ctx->getXCOFFSection(
+ ".dwloc", SectionKind::getMetadata(), /* CsectProperties */ None,
+ /* MultiSymbolsAllowed */ true, ".dwloc", XCOFF::SSUBTYP_DWLOC);
+
+ DwarfARangesSection = Ctx->getXCOFFSection(
+ ".dwarnge", SectionKind::getMetadata(), /* CsectProperties */ None,
+ /* MultiSymbolsAllowed */ true, ".dwarnge", XCOFF::SSUBTYP_DWARNGE);
+
+ DwarfRangesSection = Ctx->getXCOFFSection(
+ ".dwrnges", SectionKind::getMetadata(), /* CsectProperties */ None,
+ /* MultiSymbolsAllowed */ true, ".dwrnges", XCOFF::SSUBTYP_DWRNGES);
+
+ DwarfMacinfoSection = Ctx->getXCOFFSection(
+ ".dwmac", SectionKind::getMetadata(), /* CsectProperties */ None,
+ /* MultiSymbolsAllowed */ true, ".dwmac", XCOFF::SSUBTYP_DWMAC);
}
void MCObjectFileInfo::InitMCObjectFileInfo(const Triple &TheTriple, bool PIC,
diff --git a/llvm/lib/MC/MCObjectStreamer.cpp b/llvm/lib/MC/MCObjectStreamer.cpp
index 1c23d31f8744..299f2a719fb9 100644
--- a/llvm/lib/MC/MCObjectStreamer.cpp
+++ b/llvm/lib/MC/MCObjectStreamer.cpp
@@ -9,12 +9,14 @@
#include "llvm/MC/MCObjectStreamer.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/MC/MCAsmBackend.h"
+#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCAssembler.h"
#include "llvm/MC/MCCodeEmitter.h"
#include "llvm/MC/MCCodeView.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCDwarf.h"
#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCObjectFileInfo.h"
#include "llvm/MC/MCObjectWriter.h"
#include "llvm/MC/MCSection.h"
#include "llvm/MC/MCSymbol.h"
@@ -228,7 +230,7 @@ void MCObjectStreamer::emitValueImpl(const MCExpr *Value, unsigned Size,
MCDataFragment *DF = getOrCreateDataFragment();
flushPendingLabels(DF, DF->getContents().size());
- MCDwarfLineEntry::Make(this, getCurrentSectionOnly());
+ MCDwarfLineEntry::make(this, getCurrentSectionOnly());
// Avoid fixups when possible.
int64_t AbsValue;
@@ -385,7 +387,7 @@ void MCObjectStreamer::emitInstructionImpl(const MCInst &Inst,
// Now that a machine instruction has been assembled into this section, make
// a line entry for any .loc directive that has been seen.
- MCDwarfLineEntry::Make(this, getCurrentSectionOnly());
+ MCDwarfLineEntry::make(this, getCurrentSectionOnly());
// If this instruction doesn't need relaxation, just emit it as data.
MCAssembler &Assembler = getAssembler();
@@ -455,7 +457,7 @@ void MCObjectStreamer::emitDwarfLocDirective(unsigned FileNo, unsigned Line,
StringRef FileName) {
// In case we see two .loc directives in a row, make sure the
// first one gets a line entry.
- MCDwarfLineEntry::Make(this, getCurrentSectionOnly());
+ MCDwarfLineEntry::make(this, getCurrentSectionOnly());
this->MCStreamer::emitDwarfLocDirective(FileNo, Line, Column, Flags, Isa,
Discriminator, FileName);
@@ -505,6 +507,24 @@ void MCObjectStreamer::emitDwarfAdvanceLineAddr(int64_t LineDelta,
insert(new MCDwarfLineAddrFragment(LineDelta, *AddrDelta));
}
+void MCObjectStreamer::emitDwarfLineEndEntry(MCSection *Section,
+ MCSymbol *LastLabel) {
+ // Emit a DW_LNE_end_sequence for the end of the section.
+ // Use the section end label to compute the address delta and use INT64_MAX
+ // as the line delta which is the signal that this is actually a
+ // DW_LNE_end_sequence.
+ MCSymbol *SectionEnd = endSection(Section);
+
+ // Switch back the dwarf line section, in case endSection had to switch the
+ // section.
+ MCContext &Ctx = getContext();
+ SwitchSection(Ctx.getObjectFileInfo()->getDwarfLineSection());
+
+ const MCAsmInfo *AsmInfo = Ctx.getAsmInfo();
+ emitDwarfAdvanceLineAddr(INT64_MAX, LastLabel, SectionEnd,
+ AsmInfo->getCodePointerSize());
+}
+
void MCObjectStreamer::emitDwarfAdvanceFrameAddr(const MCSymbol *LastLabel,
const MCSymbol *Label) {
const MCExpr *AddrDelta = buildSymbolDiff(*this, Label, LastLabel);
@@ -573,7 +593,7 @@ void MCObjectStreamer::emitCVFileChecksumOffsetDirective(unsigned FileNo) {
}
void MCObjectStreamer::emitBytes(StringRef Data) {
- MCDwarfLineEntry::Make(this, getCurrentSectionOnly());
+ MCDwarfLineEntry::make(this, getCurrentSectionOnly());
MCDataFragment *DF = getOrCreateDataFragment();
flushPendingLabels(DF, DF->getContents().size());
DF->getContents().append(Data.begin(), Data.end());
@@ -850,7 +870,7 @@ void MCObjectStreamer::finishImpl() {
MCGenDwarfInfo::Emit(this);
// Dump out the dwarf file & directory tables and line tables.
- MCDwarfLineTable::Emit(this, getAssembler().getDWARFLinetableParams());
+ MCDwarfLineTable::emit(this, getAssembler().getDWARFLinetableParams());
// Emit pseudo probes for the current module.
MCPseudoProbeTable::emit(this);
diff --git a/llvm/lib/MC/MCSectionXCOFF.cpp b/llvm/lib/MC/MCSectionXCOFF.cpp
index 8c01f7f0dc49..2adddd316973 100644
--- a/llvm/lib/MC/MCSectionXCOFF.cpp
+++ b/llvm/lib/MC/MCSectionXCOFF.cpp
@@ -9,6 +9,8 @@
#include "llvm/MC/MCSectionXCOFF.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCExpr.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Format.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
@@ -68,7 +70,7 @@ void MCSectionXCOFF::PrintSwitchToSection(const MCAsmInfo &MAI, const Triple &T,
// Common csect type (uninitialized storage) does not have to print csect
// directive for section switching.
- if (getCSectType() == XCOFF::XTY_CM) {
+ if (isCsect() && getCSectType() == XCOFF::XTY_CM) {
assert((getMappingClass() == XCOFF::XMC_RW ||
getMappingClass() == XCOFF::XMC_BS ||
getMappingClass() == XCOFF::XMC_UL) &&
@@ -95,6 +97,14 @@ void MCSectionXCOFF::PrintSwitchToSection(const MCAsmInfo &MAI, const Triple &T,
return;
}
+ // XCOFF debug sections.
+ if (getKind().isMetadata() && isDwarfSect()) {
+ OS << "\n\t.dwsect "
+ << format("0x%" PRIx32, getDwarfSubtypeFlags().getValue()) << '\n';
+ OS << MAI.getPrivateLabelPrefix() << getName() << ':' << '\n';
+ return;
+ }
+
report_fatal_error("Printing for this SectionKind is unimplemented.");
}
diff --git a/llvm/lib/MC/MCStreamer.cpp b/llvm/lib/MC/MCStreamer.cpp
index b2fc54236f7f..afaa57005106 100644
--- a/llvm/lib/MC/MCStreamer.cpp
+++ b/llvm/lib/MC/MCStreamer.cpp
@@ -1019,6 +1019,11 @@ MCSymbol *MCStreamer::emitDwarfUnitLength(const Twine &Prefix,
return Hi;
}
+void MCStreamer::emitDwarfLineStartLabel(MCSymbol *StartSym) {
+ // Set the value of the symbol, as we are at the start of the line table.
+ emitLabel(StartSym);
+}
+
void MCStreamer::emitAssignment(MCSymbol *Symbol, const MCExpr *Value) {
visitUsedExpr(*Value);
Symbol->setVariableValue(Value);
diff --git a/llvm/lib/MC/MCSymbolXCOFF.cpp b/llvm/lib/MC/MCSymbolXCOFF.cpp
index b9dd2908b40b..b4c96a1ffa23 100644
--- a/llvm/lib/MC/MCSymbolXCOFF.cpp
+++ b/llvm/lib/MC/MCSymbolXCOFF.cpp
@@ -13,9 +13,6 @@ using namespace llvm;
MCSectionXCOFF *MCSymbolXCOFF::getRepresentedCsect() const {
assert(RepresentedCsect &&
"Trying to get csect representation of this symbol but none was set.");
- assert(!getName().equals(getUnqualifiedName()) &&
- "Symbol does not represent a csect; MCSectionXCOFF that represents "
- "the symbol should not be (but is) set.");
assert(getSymbolTableName().equals(RepresentedCsect->getSymbolTableName()) &&
"SymbolTableNames need to be the same for this symbol and its csect "
"representation.");
@@ -27,9 +24,6 @@ void MCSymbolXCOFF::setRepresentedCsect(MCSectionXCOFF *C) {
assert((!RepresentedCsect || RepresentedCsect == C) &&
"Trying to set a csect that doesn't match the one that this symbol is "
"already mapped to.");
- assert(!getName().equals(getUnqualifiedName()) &&
- "Symbol does not represent a csect; can only set a MCSectionXCOFF "
- "representation for a csect.");
assert(getSymbolTableName().equals(C->getSymbolTableName()) &&
"SymbolTableNames need to be the same for this symbol and its csect "
"representation.");
diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCAsmInfo.cpp b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCAsmInfo.cpp
index 2b76af279ce6..b0f52679d3d9 100644
--- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCAsmInfo.cpp
+++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCAsmInfo.cpp
@@ -63,4 +63,10 @@ PPCXCOFFMCAsmInfo::PPCXCOFFMCAsmInfo(bool Is64Bit, const Triple &T) {
// A size of 8 is only supported by the assembler under 64-bit.
Data64bitsDirective = Is64Bit ? "\t.vbyte\t8, " : nullptr;
+
+ // Debug Information
+ SupportsDebugInformation = true;
+
+ // Set up DWARF directives
+ MinInstAlignment = 4;
}
diff --git a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
index ddfca2a764d4..4e307dfc1e80 100644
--- a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
+++ b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
@@ -2303,6 +2303,11 @@ void PPCAIXAsmPrinter::emitInstruction(const MachineInstr *MI) {
}
bool PPCAIXAsmPrinter::doFinalization(Module &M) {
+ // Do streamer related finalization for DWARF.
+ if (!MAI->usesDwarfFileAndLocDirectives() && MMI->hasDebugInfo())
+ OutStreamer->doFinalizationAtSectionEnd(
+ OutStreamer->getContext().getObjectFileInfo()->getTextSection());
+
for (MCSymbol *Sym : ExtSymSDNodeSymbols)
OutStreamer->emitSymbolAttribute(Sym, MCSA_Extern);
return PPCAsmPrinter::doFinalization(M);
diff --git a/llvm/test/DebugInfo/XCOFF/empty.ll b/llvm/test/DebugInfo/XCOFF/empty.ll
new file mode 100644
index 000000000000..1e65797f4807
--- /dev/null
+++ b/llvm/test/DebugInfo/XCOFF/empty.ll
@@ -0,0 +1,436 @@
+
+; RUN: llc -mtriple powerpc-ibm-aix-xcoff < %s | \
+; RUN: FileCheck %s --check-prefix=ASM32
+; RUN: llc -mtriple powerpc64-ibm-aix-xcoff < %s | \
+; RUN: FileCheck %s --check-prefix=ASM64
+
+source_filename = "1.c"
+target datalayout = "E-m:a-p:32:32-i64:64-n32"
+
+; Function Attrs: noinline nounwind optnone
+define i32 @main() #0 !dbg !8 {
+entry:
+ %retval = alloca i32, align 4
+ store i32 0, i32* %retval, align 4
+ ret i32 0, !dbg !12
+}
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3, !4, !5, !6}
+!llvm.ident = !{!7}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 12.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None)
+!1 = !DIFile(filename: "1.c", directory: "debug")
+!2 = !{}
+!3 = !{i32 7, !"Dwarf Version", i32 4}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = !{i32 1, !"wchar_size", i32 2}
+!6 = !{i32 7, !"PIC Level", i32 2}
+!7 = !{!"clang version 12.0.0"}
+!8 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 1, type: !9, scopeLine: 2, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2)
+!9 = !DISubroutineType(types: !10)
+!10 = !{!11}
+!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!12 = !DILocation(line: 3, column: 3, scope: !8)
+
+; ASM32: .csect .text[PR],2
+; ASM32-NEXT: .file "1.c"
+; ASM32-NEXT: .globl main[DS] # -- Begin function main
+; ASM32-NEXT: .globl .main
+; ASM32-NEXT: .align 2
+; ASM32-NEXT: .csect main[DS],2
+; ASM32-NEXT: .vbyte 4, .main # @main
+; ASM32-NEXT: .vbyte 4, TOC[TC0]
+; ASM32-NEXT: .vbyte 4, 0
+; ASM32-NEXT: .csect .text[PR],2
+; ASM32-NEXT: .main:
+; ASM32-NEXT: L..func_begin0:
+; ASM32-NEXT: # %bb.0: # %entry
+; ASM32-NEXT: L..tmp0:
+; ASM32-NEXT: li 4, 0
+; ASM32-NEXT: L..tmp1:
+; ASM32-NEXT: L..tmp2:
+; ASM32-NEXT: li 3, 0
+; ASM32-NEXT: stw 4, -4(1)
+; ASM32-NEXT: blr
+; ASM32-NEXT: L..tmp3:
+; ASM32-NEXT: L..main0:
+; ASM32-NEXT: .vbyte 4, 0x00000000 # Traceback table begin
+; ASM32-NEXT: .byte 0x00 # Version = 0
+; ASM32-NEXT: .byte 0x09 # Language = CPlusPlus
+; ASM32-NEXT: .byte 0x20 # -IsGlobaLinkage, -IsOutOfLineEpilogOrPrologue
+; ASM32-NEXT: # +HasTraceBackTableOffset, -IsInternalProcedure
+; ASM32-NEXT: # -HasControlledStorage, -IsTOCless
+; ASM32-NEXT: # -IsFloatingPointPresent
+; ASM32-NEXT: # -IsFloatingPointOperationLogOrAbortEnabled
+; ASM32-NEXT: .byte 0x40 # -IsInterruptHandler, +IsFunctionNamePresent, -IsAllocaUsed
+; ASM32-NEXT: # OnConditionDirective = 0, -IsCRSaved, -IsLRSaved
+; ASM32-NEXT: .byte 0x80 # +IsBackChainStored, -IsFixup, NumOfFPRsSaved = 0
+; ASM32-NEXT: .byte 0x00 # -HasVectorInfo, -HasExtensionTable, NumOfGPRsSaved = 0
+; ASM32-NEXT: .byte 0x00 # NumberOfFixedParms = 0
+; ASM32-NEXT: .byte 0x01 # NumberOfFPParms = 0, +HasParmsOnStack
+; ASM32-NEXT: .vbyte 4, L..main0-.main # Function size
+; ASM32-NEXT: .vbyte 2, 0x0004 # Function name len = 4
+; ASM32-NEXT: .byte 'm,'a,'i,'n # Function Name
+; ASM32-NEXT: L..func_end0:
+; ASM32-NEXT: # -- End function
+; ASM32-NEXT: L..sec_end0:
+; ASM32: .dwsect 0x60000
+; ASM32-NEXT: L...dwabrev:
+; ASM32-NEXT: .byte 1 # Abbreviation Code
+; ASM32-NEXT: .byte 17 # DW_TAG_compile_unit
+; ASM32-NEXT: .byte 1 # DW_CHILDREN_yes
+; ASM32-NEXT: .byte 37 # DW_AT_producer
+; ASM32-NEXT: .byte 14 # DW_FORM_strp
+; ASM32-NEXT: .byte 19 # DW_AT_language
+; ASM32-NEXT: .byte 5 # DW_FORM_data2
+; ASM32-NEXT: .byte 3 # DW_AT_name
+; ASM32-NEXT: .byte 14 # DW_FORM_strp
+; ASM32-NEXT: .byte 16 # DW_AT_stmt_list
+; ASM32-NEXT: .byte 23 # DW_FORM_sec_offset
+; ASM32-NEXT: .byte 27 # DW_AT_comp_dir
+; ASM32-NEXT: .byte 14 # DW_FORM_strp
+; ASM32-NEXT: .byte 17 # DW_AT_low_pc
+; ASM32-NEXT: .byte 1 # DW_FORM_addr
+; ASM32-NEXT: .byte 18 # DW_AT_high_pc
+; ASM32-NEXT: .byte 6 # DW_FORM_data4
+; ASM32-NEXT: .byte 0 # EOM(1)
+; ASM32-NEXT: .byte 0 # EOM(2)
+; ASM32-NEXT: .byte 2 # Abbreviation Code
+; ASM32-NEXT: .byte 46 # DW_TAG_subprogram
+; ASM32-NEXT: .byte 0 # DW_CHILDREN_no
+; ASM32-NEXT: .byte 17 # DW_AT_low_pc
+; ASM32-NEXT: .byte 1 # DW_FORM_addr
+; ASM32-NEXT: .byte 18 # DW_AT_high_pc
+; ASM32-NEXT: .byte 6 # DW_FORM_data4
+; ASM32-NEXT: .byte 64 # DW_AT_frame_base
+; ASM32-NEXT: .byte 24 # DW_FORM_exprloc
+; ASM32-NEXT: .byte 3 # DW_AT_name
+; ASM32-NEXT: .byte 14 # DW_FORM_strp
+; ASM32-NEXT: .byte 58 # DW_AT_decl_file
+; ASM32-NEXT: .byte 11 # DW_FORM_data1
+; ASM32-NEXT: .byte 59 # DW_AT_decl_line
+; ASM32-NEXT: .byte 11 # DW_FORM_data1
+; ASM32-NEXT: .byte 39 # DW_AT_prototyped
+; ASM32-NEXT: .byte 25 # DW_FORM_flag_present
+; ASM32-NEXT: .byte 73 # DW_AT_type
+; ASM32-NEXT: .byte 19 # DW_FORM_ref4
+; ASM32-NEXT: .byte 63 # DW_AT_external
+; ASM32-NEXT: .byte 25 # DW_FORM_flag_present
+; ASM32-NEXT: .byte 0 # EOM(1)
+; ASM32-NEXT: .byte 0 # EOM(2)
+; ASM32-NEXT: .byte 3 # Abbreviation Code
+; ASM32-NEXT: .byte 36 # DW_TAG_base_type
+; ASM32-NEXT: .byte 0 # DW_CHILDREN_no
+; ASM32-NEXT: .byte 3 # DW_AT_name
+; ASM32-NEXT: .byte 14 # DW_FORM_strp
+; ASM32-NEXT: .byte 62 # DW_AT_encoding
+; ASM32-NEXT: .byte 11 # DW_FORM_data1
+; ASM32-NEXT: .byte 11 # DW_AT_byte_size
+; ASM32-NEXT: .byte 11 # DW_FORM_data1
+; ASM32-NEXT: .byte 0 # EOM(1)
+; ASM32-NEXT: .byte 0 # EOM(2)
+; ASM32-NEXT: .byte 0 # EOM(3)
+; ASM32: .dwsect 0x10000
+; ASM32-NEXT: L...dwinfo:
+; ASM32-NEXT: L..cu_begin0:
+; ASM32-NEXT: .vbyte 2, 4 # DWARF version number
+; ASM32-NEXT: .vbyte 4, L...dwabrev # Offset Into Abbrev. Section
+; ASM32-NEXT: .byte 4 # Address Size (in bytes)
+; ASM32-NEXT: .byte 1 # Abbrev [1] 0xb:0x38 DW_TAG_compile_unit
+; ASM32-NEXT: .vbyte 4, L..info_string0 # DW_AT_producer
+; ASM32-NEXT: .vbyte 2, 12 # DW_AT_language
+; ASM32-NEXT: .vbyte 4, L..info_string1 # DW_AT_name
+; ASM32-NEXT: .vbyte 4, L..line_table_start0 # DW_AT_stmt_list
+; ASM32-NEXT: .vbyte 4, L..info_string2 # DW_AT_comp_dir
+; ASM32-NEXT: .vbyte 4, L..func_begin0 # DW_AT_low_pc
+; ASM32-NEXT: .vbyte 4, L..func_end0-L..func_begin0 # DW_AT_high_pc
+; ASM32-NEXT: .byte 2 # Abbrev [2] 0x26:0x15 DW_TAG_subprogram
+; ASM32-NEXT: .vbyte 4, L..func_begin0 # DW_AT_low_pc
+; ASM32-NEXT: .vbyte 4, L..func_end0-L..func_begin0 # DW_AT_high_pc
+; ASM32-NEXT: .byte 1 # DW_AT_frame_base
+; ASM32-NEXT: .byte 81
+; ASM32-NEXT: .vbyte 4, L..info_string3 # DW_AT_name
+; ASM32-NEXT: .byte 1 # DW_AT_decl_file
+; ASM32-NEXT: .byte 1 # DW_AT_decl_line
+; ASM32-NEXT: # DW_AT_prototyped
+; ASM32-NEXT: .vbyte 4, 59 # DW_AT_type
+; ASM32-NEXT: # DW_AT_external
+; ASM32-NEXT: .byte 3 # Abbrev [3] 0x3b:0x7 DW_TAG_base_type
+; ASM32-NEXT: .vbyte 4, L..info_string4 # DW_AT_name
+; ASM32-NEXT: .byte 5 # DW_AT_encoding
+; ASM32-NEXT: .byte 4 # DW_AT_byte_size
+; ASM32-NEXT: .byte 0 # End Of Children Mark
+; ASM32-NEXT: L..debug_info_end0:
+; ASM32: .dwsect 0x70000
+; ASM32-NEXT: L...dwstr:
+; ASM32-NEXT: L..info_string0:
+; ASM32-NEXT: .byte 'c,'l,'a,'n,'g,' ,'v,'e,'r,'s,'i,'o,'n,' ,'1,'2,'.,'0,'.,'0,0000 # string offset=0
+; ASM32-NEXT: L..info_string1:
+; ASM32-NEXT: .byte '1,'.,'c,0000 # string offset=21
+; ASM32-NEXT: L..info_string2:
+; ASM32-NEXT: .byte 'd,'e,'b,'u,'g,0000 # string offset=25
+; ASM32-NEXT: L..info_string3:
+; ASM32-NEXT: .byte 'm,'a,'i,'n,0000 # string offset=31
+; ASM32-NEXT: L..info_string4:
+; ASM32-NEXT: .byte 'i,'n,'t,0000 # string offset=36
+; ASM32-NEXT: .toc
+; ASM32: .dwsect 0x20000
+; ASM32-NEXT: L...dwline:
+; ASM32-NEXT: L..debug_line_0:
+; ASM32-NEXT: .set L..line_table_start0, L..debug_line_0-4
+; ASM32-NEXT: .vbyte 2, 4
+; ASM32-NEXT: .vbyte 4, L..tmp5-L..tmp4
+; ASM32-NEXT: L..tmp4:
+; ASM32-NEXT: .byte 4
+; ASM32-NEXT: .byte 1
+; ASM32-NEXT: .byte 1
+; ASM32-NEXT: .byte -5
+; ASM32-NEXT: .byte 14
+; ASM32-NEXT: .byte 13
+; ASM32-NEXT: .byte 0
+; ASM32-NEXT: .byte 1
+; ASM32-NEXT: .byte 1
+; ASM32-NEXT: .byte 1
+; ASM32-NEXT: .byte 1
+; ASM32-NEXT: .byte 0
+; ASM32-NEXT: .byte 0
+; ASM32-NEXT: .byte 0
+; ASM32-NEXT: .byte 1
+; ASM32-NEXT: .byte 0
+; ASM32-NEXT: .byte 0
+; ASM32-NEXT: .byte 1
+; ASM32-NEXT: .byte 'd,'e,'b,'u,'g
+; ASM32-NEXT: .byte 0
+; ASM32-NEXT: .byte 0
+; ASM32-NEXT: .byte '1,'.,'c
+; ASM32-NEXT: .byte 0
+; ASM32-NEXT: .byte 1
+; ASM32-NEXT: .byte 0
+; ASM32-NEXT: .byte 0
+; ASM32-NEXT: .byte 0
+; ASM32-NEXT: L..tmp5:
+; ASM32-NEXT: .byte 0 # Set address to L..tmp0
+; ASM32-NEXT: .byte 5
+; ASM32-NEXT: .byte 2
+; ASM32-NEXT: .vbyte 4, L..tmp0
+; ASM32-NEXT: .byte 19 # Start sequence
+; ASM32-NEXT: .byte 5
+; ASM32-NEXT: .byte 3
+; ASM32-NEXT: .byte 10
+; ASM32-NEXT: .byte 0 # Set address to L..tmp2
+; ASM32-NEXT: .byte 5
+; ASM32-NEXT: .byte 2
+; ASM32-NEXT: .vbyte 4, L..tmp2
+; ASM32-NEXT: .byte 3 # Advance line 1
+; ASM32-NEXT: .byte 1
+; ASM32-NEXT: .byte 1
+; ASM32-NEXT: .byte 0 # Set address to L..sec_end0
+; ASM32-NEXT: .byte 5
+; ASM32-NEXT: .byte 2
+; ASM32-NEXT: .vbyte 4, L..sec_end0
+; ASM32-NEXT: .byte 0 # End sequence
+; ASM32-NEXT: .byte 1
+; ASM32-NEXT: .byte 1
+; ASM32-NEXT: L..debug_line_end0:
+
+; ASM64: .csect .text[PR],2
+; ASM64-NEXT: .file "1.c"
+; ASM64-NEXT: .globl main[DS] # -- Begin function main
+; ASM64-NEXT: .globl .main
+; ASM64-NEXT: .align 2
+; ASM64-NEXT: .csect main[DS],3
+; ASM64-NEXT: .vbyte 8, .main # @main
+; ASM64-NEXT: .vbyte 8, TOC[TC0]
+; ASM64-NEXT: .vbyte 8, 0
+; ASM64-NEXT: .csect .text[PR],2
+; ASM64-NEXT: .main:
+; ASM64-NEXT: L..func_begin0:
+; ASM64-NEXT: # %bb.0: # %entry
+; ASM64-NEXT: L..tmp0:
+; ASM64-NEXT: li 4, 0
+; ASM64-NEXT: L..tmp1:
+; ASM64-NEXT: L..tmp2:
+; ASM64-NEXT: li 3, 0
+; ASM64-NEXT: stw 4, -4(1)
+; ASM64-NEXT: blr
+; ASM64-NEXT: L..tmp3:
+; ASM64-NEXT: L..main0:
+; ASM64-NEXT: .vbyte 4, 0x00000000 # Traceback table begin
+; ASM64-NEXT: .byte 0x00 # Version = 0
+; ASM64-NEXT: .byte 0x09 # Language = CPlusPlus
+; ASM64-NEXT: .byte 0x20 # -IsGlobaLinkage, -IsOutOfLineEpilogOrPrologue
+; ASM64-NEXT: # +HasTraceBackTableOffset, -IsInternalProcedure
+; ASM64-NEXT: # -HasControlledStorage, -IsTOCless
+; ASM64-NEXT: # -IsFloatingPointPresent
+; ASM64-NEXT: # -IsFloatingPointOperationLogOrAbortEnabled
+; ASM64-NEXT: .byte 0x40 # -IsInterruptHandler, +IsFunctionNamePresent, -IsAllocaUsed
+; ASM64-NEXT: # OnConditionDirective = 0, -IsCRSaved, -IsLRSaved
+; ASM64-NEXT: .byte 0x80 # +IsBackChainStored, -IsFixup, NumOfFPRsSaved = 0
+; ASM64-NEXT: .byte 0x00 # -HasVectorInfo, -HasExtensionTable, NumOfGPRsSaved = 0
+; ASM64-NEXT: .byte 0x00 # NumberOfFixedParms = 0
+; ASM64-NEXT: .byte 0x01 # NumberOfFPParms = 0, +HasParmsOnStack
+; ASM64-NEXT: .vbyte 4, L..main0-.main # Function size
+; ASM64-NEXT: .vbyte 2, 0x0004 # Function name len = 4
+; ASM64-NEXT: .byte 'm,'a,'i,'n # Function Name
+; ASM64-NEXT: L..func_end0:
+; ASM64-NEXT: # -- End function
+; ASM64-NEXT: L..sec_end0:
+; ASM64: .dwsect 0x60000
+; ASM64-NEXT: L...dwabrev:
+; ASM64-NEXT: .byte 1 # Abbreviation Code
+; ASM64-NEXT: .byte 17 # DW_TAG_compile_unit
+; ASM64-NEXT: .byte 1 # DW_CHILDREN_yes
+; ASM64-NEXT: .byte 37 # DW_AT_producer
+; ASM64-NEXT: .byte 14 # DW_FORM_strp
+; ASM64-NEXT: .byte 19 # DW_AT_language
+; ASM64-NEXT: .byte 5 # DW_FORM_data2
+; ASM64-NEXT: .byte 3 # DW_AT_name
+; ASM64-NEXT: .byte 14 # DW_FORM_strp
+; ASM64-NEXT: .byte 16 # DW_AT_stmt_list
+; ASM64-NEXT: .byte 23 # DW_FORM_sec_offset
+; ASM64-NEXT: .byte 27 # DW_AT_comp_dir
+; ASM64-NEXT: .byte 14 # DW_FORM_strp
+; ASM64-NEXT: .byte 17 # DW_AT_low_pc
+; ASM64-NEXT: .byte 1 # DW_FORM_addr
+; ASM64-NEXT: .byte 18 # DW_AT_high_pc
+; ASM64-NEXT: .byte 6 # DW_FORM_data4
+; ASM64-NEXT: .byte 0 # EOM(1)
+; ASM64-NEXT: .byte 0 # EOM(2)
+; ASM64-NEXT: .byte 2 # Abbreviation Code
+; ASM64-NEXT: .byte 46 # DW_TAG_subprogram
+; ASM64-NEXT: .byte 0 # DW_CHILDREN_no
+; ASM64-NEXT: .byte 17 # DW_AT_low_pc
+; ASM64-NEXT: .byte 1 # DW_FORM_addr
+; ASM64-NEXT: .byte 18 # DW_AT_high_pc
+; ASM64-NEXT: .byte 6 # DW_FORM_data4
+; ASM64-NEXT: .byte 64 # DW_AT_frame_base
+; ASM64-NEXT: .byte 24 # DW_FORM_exprloc
+; ASM64-NEXT: .byte 3 # DW_AT_name
+; ASM64-NEXT: .byte 14 # DW_FORM_strp
+; ASM64-NEXT: .byte 58 # DW_AT_decl_file
+; ASM64-NEXT: .byte 11 # DW_FORM_data1
+; ASM64-NEXT: .byte 59 # DW_AT_decl_line
+; ASM64-NEXT: .byte 11 # DW_FORM_data1
+; ASM64-NEXT: .byte 39 # DW_AT_prototyped
+; ASM64-NEXT: .byte 25 # DW_FORM_flag_present
+; ASM64-NEXT: .byte 73 # DW_AT_type
+; ASM64-NEXT: .byte 19 # DW_FORM_ref4
+; ASM64-NEXT: .byte 63 # DW_AT_external
+; ASM64-NEXT: .byte 25 # DW_FORM_flag_present
+; ASM64-NEXT: .byte 0 # EOM(1)
+; ASM64-NEXT: .byte 0 # EOM(2)
+; ASM64-NEXT: .byte 3 # Abbreviation Code
+; ASM64-NEXT: .byte 36 # DW_TAG_base_type
+; ASM64-NEXT: .byte 0 # DW_CHILDREN_no
+; ASM64-NEXT: .byte 3 # DW_AT_name
+; ASM64-NEXT: .byte 14 # DW_FORM_strp
+; ASM64-NEXT: .byte 62 # DW_AT_encoding
+; ASM64-NEXT: .byte 11 # DW_FORM_data1
+; ASM64-NEXT: .byte 11 # DW_AT_byte_size
+; ASM64-NEXT: .byte 11 # DW_FORM_data1
+; ASM64-NEXT: .byte 0 # EOM(1)
+; ASM64-NEXT: .byte 0 # EOM(2)
+; ASM64-NEXT: .byte 0 # EOM(3)
+; ASM64: .dwsect 0x10000
+; ASM64-NEXT: L...dwinfo:
+; ASM64-NEXT: L..cu_begin0:
+; ASM64-NEXT: .vbyte 2, 4 # DWARF version number
+; ASM64-NEXT: .vbyte 8, L...dwabrev # Offset Into Abbrev. Section
+; ASM64-NEXT: .byte 8 # Address Size (in bytes)
+; ASM64-NEXT: .byte 1 # Abbrev [1] 0x17:0x58 DW_TAG_compile_unit
+; ASM64-NEXT: .vbyte 8, L..info_string0 # DW_AT_producer
+; ASM64-NEXT: .vbyte 2, 12 # DW_AT_language
+; ASM64-NEXT: .vbyte 8, L..info_string1 # DW_AT_name
+; ASM64-NEXT: .vbyte 8, L..line_table_start0 # DW_AT_stmt_list
+; ASM64-NEXT: .vbyte 8, L..info_string2 # DW_AT_comp_dir
+; ASM64-NEXT: .vbyte 8, L..func_begin0 # DW_AT_low_pc
+; ASM64-NEXT: .vbyte 4, L..func_end0-L..func_begin0 # DW_AT_high_pc
+; ASM64-NEXT: .byte 2 # Abbrev [2] 0x46:0x1d DW_TAG_subprogram
+; ASM64-NEXT: .vbyte 8, L..func_begin0 # DW_AT_low_pc
+; ASM64-NEXT: .vbyte 4, L..func_end0-L..func_begin0 # DW_AT_high_pc
+; ASM64-NEXT: .byte 1 # DW_AT_frame_base
+; ASM64-NEXT: .byte 81
+; ASM64-NEXT: .vbyte 8, L..info_string3 # DW_AT_name
+; ASM64-NEXT: .byte 1 # DW_AT_decl_file
+; ASM64-NEXT: .byte 1 # DW_AT_decl_line
+; ASM64-NEXT: # DW_AT_prototyped
+; ASM64-NEXT: .vbyte 4, 99 # DW_AT_type
+; ASM64-NEXT: # DW_AT_external
+; ASM64-NEXT: .byte 3 # Abbrev [3] 0x63:0xb DW_TAG_base_type
+; ASM64-NEXT: .vbyte 8, L..info_string4 # DW_AT_name
+; ASM64-NEXT: .byte 5 # DW_AT_encoding
+; ASM64-NEXT: .byte 4 # DW_AT_byte_size
+; ASM64-NEXT: .byte 0 # End Of Children Mark
+; ASM64-NEXT: L..debug_info_end0:
+; ASM64: .dwsect 0x70000
+; ASM64-NEXT: L...dwstr:
+; ASM64-NEXT: L..info_string0:
+; ASM64-NEXT: .byte 'c,'l,'a,'n,'g,' ,'v,'e,'r,'s,'i,'o,'n,' ,'1,'2,'.,'0,'.,'0,0000 # string offset=0
+; ASM64-NEXT: L..info_string1:
+; ASM64-NEXT: .byte '1,'.,'c,0000 # string offset=21
+; ASM64-NEXT: L..info_string2:
+; ASM64-NEXT: .byte 'd,'e,'b,'u,'g,0000 # string offset=25
+; ASM64-NEXT: L..info_string3:
+; ASM64-NEXT: .byte 'm,'a,'i,'n,0000 # string offset=31
+; ASM64-NEXT: L..info_string4:
+; ASM64-NEXT: .byte 'i,'n,'t,0000 # string offset=36
+; ASM64-NEXT: .toc
+; ASM64: .dwsect 0x20000
+; ASM64-NEXT: L...dwline:
+; ASM64-NEXT: L..debug_line_0:
+; ASM64-NEXT: .set L..line_table_start0, L..debug_line_0-12
+; ASM64-NEXT: .vbyte 2, 4
+; ASM64-NEXT: .vbyte 8, L..tmp5-L..tmp4
+; ASM64-NEXT: L..tmp4:
+; ASM64-NEXT: .byte 4
+; ASM64-NEXT: .byte 1
+; ASM64-NEXT: .byte 1
+; ASM64-NEXT: .byte -5
+; ASM64-NEXT: .byte 14
+; ASM64-NEXT: .byte 13
+; ASM64-NEXT: .byte 0
+; ASM64-NEXT: .byte 1
+; ASM64-NEXT: .byte 1
+; ASM64-NEXT: .byte 1
+; ASM64-NEXT: .byte 1
+; ASM64-NEXT: .byte 0
+; ASM64-NEXT: .byte 0
+; ASM64-NEXT: .byte 0
+; ASM64-NEXT: .byte 1
+; ASM64-NEXT: .byte 0
+; ASM64-NEXT: .byte 0
+; ASM64-NEXT: .byte 1
+; ASM64-NEXT: .byte 'd,'e,'b,'u,'g
+; ASM64-NEXT: .byte 0
+; ASM64-NEXT: .byte 0
+; ASM64-NEXT: .byte '1,'.,'c
+; ASM64-NEXT: .byte 0
+; ASM64-NEXT: .byte 1
+; ASM64-NEXT: .byte 0
+; ASM64-NEXT: .byte 0
+; ASM64-NEXT: .byte 0
+; ASM64-NEXT: L..tmp5:
+; ASM64-NEXT: .byte 0 # Set address to L..tmp0
+; ASM64-NEXT: .byte 9
+; ASM64-NEXT: .byte 2
+; ASM64-NEXT: .vbyte 8, L..tmp0
+; ASM64-NEXT: .byte 19 # Start sequence
+; ASM64-NEXT: .byte 5
+; ASM64-NEXT: .byte 3
+; ASM64-NEXT: .byte 10
+; ASM64-NEXT: .byte 0 # Set address to L..tmp2
+; ASM64-NEXT: .byte 9
+; ASM64-NEXT: .byte 2
+; ASM64-NEXT: .vbyte 8, L..tmp2
+; ASM64-NEXT: .byte 3 # Advance line 1
+; ASM64-NEXT: .byte 1
+; ASM64-NEXT: .byte 1
+; ASM64-NEXT: .byte 0 # Set address to L..sec_end0
+; ASM64-NEXT: .byte 9
+; ASM64-NEXT: .byte 2
+; ASM64-NEXT: .vbyte 8, L..sec_end0
+; ASM64-NEXT: .byte 0 # End sequence
+; ASM64-NEXT: .byte 1
+; ASM64-NEXT: .byte 1
+; ASM64-NEXT: L..debug_line_end0:
diff --git a/llvm/test/DebugInfo/XCOFF/explicit-section.ll b/llvm/test/DebugInfo/XCOFF/explicit-section.ll
new file mode 100644
index 000000000000..cf6caa236b12
--- /dev/null
+++ b/llvm/test/DebugInfo/XCOFF/explicit-section.ll
@@ -0,0 +1,338 @@
+
+; RUN: llc -mtriple powerpc-ibm-aix-xcoff < %s | \
+; RUN: FileCheck %s
+
+source_filename = "2.c"
+target datalayout = "E-m:a-p:32:32-i64:64-n32"
+
+; Function Attrs: noinline nounwind optnone
+define i32 @bar() #0 !dbg !8 {
+entry:
+ ret i32 1, !dbg !13
+}
+
+; Function Attrs: noinline nounwind optnone
+define i32 @main() #0 section "explicit_main_sec" !dbg !14 {
+entry:
+ %retval = alloca i32, align 4
+ store i32 0, i32* %retval, align 4
+ %call = call i32 @bar(), !dbg !15
+ ret i32 %call, !dbg !16
+}
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3, !4, !5, !6}
+!llvm.ident = !{!7}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 13.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None)
+!1 = !DIFile(filename: "2.c", directory: "debug")
+!2 = !{}
+!3 = !{i32 7, !"Dwarf Version", i32 3}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = !{i32 1, !"wchar_size", i32 2}
+!6 = !{i32 7, !"PIC Level", i32 2}
+!7 = !{!"clang version 13.0.0"}
+!8 = distinct !DISubprogram(name: "bar", scope: !9, file: !9, line: 1, type: !10, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2)
+!9 = !DIFile(filename: "2.c", directory: "debug")
+!10 = !DISubroutineType(types: !11)
+!11 = !{!12}
+!12 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!13 = !DILocation(line: 1, column: 12, scope: !8)
+!14 = distinct !DISubprogram(name: "main", scope: !9, file: !9, line: 2, type: !10, scopeLine: 2, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2)
+!15 = !DILocation(line: 3, column: 10, scope: !14)
+!16 = !DILocation(line: 3, column: 3, scope: !14)
+
+; CHECK: .csect .text[PR],2
+; CHECK-NEXT: .file "2.c"
+; CHECK-NEXT: .globl bar[DS] # -- Begin function bar
+; CHECK-NEXT: .globl .bar
+; CHECK-NEXT: .align 2
+; CHECK-NEXT: .csect bar[DS],2
+; CHECK-NEXT: .vbyte 4, .bar # @bar
+; CHECK-NEXT: .vbyte 4, TOC[TC0]
+; CHECK-NEXT: .vbyte 4, 0
+; CHECK-NEXT: .csect .text[PR],2
+; CHECK-NEXT: .bar:
+; CHECK-NEXT: L..func_begin0:
+; CHECK-NEXT: # %bb.0: # %entry
+; CHECK-NEXT: L..tmp0:
+; CHECK-NEXT: L..tmp1:
+; CHECK-NEXT: li 3, 1
+; CHECK-NEXT: blr
+; CHECK-NEXT: L..tmp2:
+; CHECK-NEXT: L..bar0:
+; CHECK-NEXT: .vbyte 4, 0x00000000 # Traceback table begin
+; CHECK-NEXT: .byte 0x00 # Version = 0
+; CHECK-NEXT: .byte 0x09 # Language = CPlusPlus
+; CHECK-NEXT: .byte 0x20 # -IsGlobaLinkage, -IsOutOfLineEpilogOrPrologue
+; CHECK-NEXT: # +HasTraceBackTableOffset, -IsInternalProcedure
+; CHECK-NEXT: # -HasControlledStorage, -IsTOCless
+; CHECK-NEXT: # -IsFloatingPointPresent
+; CHECK-NEXT: # -IsFloatingPointOperationLogOrAbortEnabled
+; CHECK-NEXT: .byte 0x40 # -IsInterruptHandler, +IsFunctionNamePresent, -IsAllocaUsed
+; CHECK-NEXT: # OnConditionDirective = 0, -IsCRSaved, -IsLRSaved
+; CHECK-NEXT: .byte 0x80 # +IsBackChainStored, -IsFixup, NumOfFPRsSaved = 0
+; CHECK-NEXT: .byte 0x00 # -HasVectorInfo, -HasExtensionTable, NumOfGPRsSaved = 0
+; CHECK-NEXT: .byte 0x00 # NumberOfFixedParms = 0
+; CHECK-NEXT: .byte 0x01 # NumberOfFPParms = 0, +HasParmsOnStack
+; CHECK-NEXT: .vbyte 4, L..bar0-.bar # Function size
+; CHECK-NEXT: .vbyte 2, 0x0003 # Function name len = 3
+; CHECK-NEXT: .byte 'b,'a,'r # Function Name
+; CHECK-NEXT: L..func_end0:
+; CHECK-NEXT: # -- End function
+; CHECK-NEXT: .csect explicit_main_sec[PR],2
+; CHECK-NEXT: .globl main[DS] # -- Begin function main
+; CHECK-NEXT: .globl .main
+; CHECK-NEXT: .align 2
+; CHECK-NEXT: .csect main[DS],2
+; CHECK-NEXT: .vbyte 4, .main # @main
+; CHECK-NEXT: .vbyte 4, TOC[TC0]
+; CHECK-NEXT: .vbyte 4, 0
+; CHECK-NEXT: .csect explicit_main_sec[PR],2
+; CHECK-NEXT: .main:
+; CHECK-NEXT: L..func_begin1:
+; CHECK-NEXT: # %bb.0: # %entry
+; CHECK-NEXT: L..tmp3:
+; CHECK-NEXT: mflr 0
+; CHECK-NEXT: stw 0, 8(1)
+; CHECK-NEXT: stwu 1, -64(1)
+; CHECK-NEXT: li 3, 0
+; CHECK-NEXT: stw 3, 60(1)
+; CHECK-NEXT: L..tmp4:
+; CHECK-NEXT: L..tmp5:
+; CHECK-NEXT: bl .bar
+; CHECK-NEXT: nop
+; CHECK-NEXT: L..tmp6:
+; CHECK-NEXT: addi 1, 1, 64
+; CHECK-NEXT: lwz 0, 8(1)
+; CHECK-NEXT: mtlr 0
+; CHECK-NEXT: blr
+; CHECK-NEXT: L..tmp7:
+; CHECK-NEXT: L..main0:
+; CHECK-NEXT: .vbyte 4, 0x00000000 # Traceback table begin
+; CHECK-NEXT: .byte 0x00 # Version = 0
+; CHECK-NEXT: .byte 0x09 # Language = CPlusPlus
+; CHECK-NEXT: .byte 0x22 # -IsGlobaLinkage, -IsOutOfLineEpilogOrPrologue
+; CHECK-NEXT: # +HasTraceBackTableOffset, -IsInternalProcedure
+; CHECK-NEXT: # -HasControlledStorage, -IsTOCless
+; CHECK-NEXT: # +IsFloatingPointPresent
+; CHECK-NEXT: # -IsFloatingPointOperationLogOrAbortEnabled
+; CHECK-NEXT: .byte 0x41 # -IsInterruptHandler, +IsFunctionNamePresent, -IsAllocaUsed
+; CHECK-NEXT: # OnConditionDirective = 0, -IsCRSaved, +IsLRSaved
+; CHECK-NEXT: .byte 0x80 # +IsBackChainStored, -IsFixup, NumOfFPRsSaved = 0
+; CHECK-NEXT: .byte 0x00 # -HasVectorInfo, -HasExtensionTable, NumOfGPRsSaved = 0
+; CHECK-NEXT: .byte 0x00 # NumberOfFixedParms = 0
+; CHECK-NEXT: .byte 0x01 # NumberOfFPParms = 0, +HasParmsOnStack
+; CHECK-NEXT: .vbyte 4, L..main0-.main # Function size
+; CHECK-NEXT: .vbyte 2, 0x0004 # Function name len = 4
+; CHECK-NEXT: .byte 'm,'a,'i,'n # Function Name
+; CHECK-NEXT: L..func_end1:
+; CHECK-NEXT: # -- End function
+; CHECK-NEXT: L..sec_end0:
+; CHECK: .dwsect 0x60000
+; CHECK-NEXT: L...dwabrev:
+; CHECK-NEXT: .byte 1 # Abbreviation Code
+; CHECK-NEXT: .byte 17 # DW_TAG_compile_unit
+; CHECK-NEXT: .byte 1 # DW_CHILDREN_yes
+; CHECK-NEXT: .byte 37 # DW_AT_producer
+; CHECK-NEXT: .byte 14 # DW_FORM_strp
+; CHECK-NEXT: .byte 19 # DW_AT_language
+; CHECK-NEXT: .byte 5 # DW_FORM_data2
+; CHECK-NEXT: .byte 3 # DW_AT_name
+; CHECK-NEXT: .byte 14 # DW_FORM_strp
+; CHECK-NEXT: .byte 16 # DW_AT_stmt_list
+; CHECK-NEXT: .byte 6 # DW_FORM_data4
+; CHECK-NEXT: .byte 27 # DW_AT_comp_dir
+; CHECK-NEXT: .byte 14 # DW_FORM_strp
+; CHECK-NEXT: .byte 17 # DW_AT_low_pc
+; CHECK-NEXT: .byte 1 # DW_FORM_addr
+; CHECK-NEXT: .byte 85 # DW_AT_ranges
+; CHECK-NEXT: .byte 6 # DW_FORM_data4
+; CHECK-NEXT: .byte 0 # EOM(1)
+; CHECK-NEXT: .byte 0 # EOM(2)
+; CHECK-NEXT: .byte 2 # Abbreviation Code
+; CHECK-NEXT: .byte 46 # DW_TAG_subprogram
+; CHECK-NEXT: .byte 0 # DW_CHILDREN_no
+; CHECK-NEXT: .byte 17 # DW_AT_low_pc
+; CHECK-NEXT: .byte 1 # DW_FORM_addr
+; CHECK-NEXT: .byte 18 # DW_AT_high_pc
+; CHECK-NEXT: .byte 1 # DW_FORM_addr
+; CHECK-NEXT: .byte 64 # DW_AT_frame_base
+; CHECK-NEXT: .byte 10 # DW_FORM_block1
+; CHECK-NEXT: .byte 3 # DW_AT_name
+; CHECK-NEXT: .byte 14 # DW_FORM_strp
+; CHECK-NEXT: .byte 58 # DW_AT_decl_file
+; CHECK-NEXT: .byte 11 # DW_FORM_data1
+; CHECK-NEXT: .byte 59 # DW_AT_decl_line
+; CHECK-NEXT: .byte 11 # DW_FORM_data1
+; CHECK-NEXT: .byte 73 # DW_AT_type
+; CHECK-NEXT: .byte 19 # DW_FORM_ref4
+; CHECK-NEXT: .byte 63 # DW_AT_external
+; CHECK-NEXT: .byte 12 # DW_FORM_flag
+; CHECK-NEXT: .byte 0 # EOM(1)
+; CHECK-NEXT: .byte 0 # EOM(2)
+; CHECK-NEXT: .byte 3 # Abbreviation Code
+; CHECK-NEXT: .byte 36 # DW_TAG_base_type
+; CHECK-NEXT: .byte 0 # DW_CHILDREN_no
+; CHECK-NEXT: .byte 3 # DW_AT_name
+; CHECK-NEXT: .byte 14 # DW_FORM_strp
+; CHECK-NEXT: .byte 62 # DW_AT_encoding
+; CHECK-NEXT: .byte 11 # DW_FORM_data1
+; CHECK-NEXT: .byte 11 # DW_AT_byte_size
+; CHECK-NEXT: .byte 11 # DW_FORM_data1
+; CHECK-NEXT: .byte 0 # EOM(1)
+; CHECK-NEXT: .byte 0 # EOM(2)
+; CHECK-NEXT: .byte 0 # EOM(3)
+; CHECK: .dwsect 0x10000
+; CHECK-NEXT: L...dwinfo:
+; CHECK-NEXT: L..cu_begin0:
+; CHECK-NEXT: .vbyte 2, 3 # DWARF version number
+; CHECK-NEXT: .vbyte 4, L...dwabrev # Offset Into Abbrev. Section
+; CHECK-NEXT: .byte 4 # Address Size (in bytes)
+; CHECK-NEXT: .byte 1 # Abbrev [1] 0xb:0x4f DW_TAG_compile_unit
+; CHECK-NEXT: .vbyte 4, L..info_string0 # DW_AT_producer
+; CHECK-NEXT: .vbyte 2, 12 # DW_AT_language
+; CHECK-NEXT: .vbyte 4, L..info_string1 # DW_AT_name
+; CHECK-NEXT: .vbyte 4, L..line_table_start0 # DW_AT_stmt_list
+; CHECK-NEXT: .vbyte 4, L..info_string2 # DW_AT_comp_dir
+; CHECK-NEXT: .vbyte 4, 0 # DW_AT_low_pc
+; CHECK-NEXT: .vbyte 4, L..debug_ranges0 # DW_AT_ranges
+; CHECK-NEXT: .byte 2 # Abbrev [2] 0x26:0x16 DW_TAG_subprogram
+; CHECK-NEXT: .vbyte 4, L..func_begin0 # DW_AT_low_pc
+; CHECK-NEXT: .vbyte 4, L..func_end0 # DW_AT_high_pc
+; CHECK-NEXT: .byte 1 # DW_AT_frame_base
+; CHECK-NEXT: .byte 81
+; CHECK-NEXT: .vbyte 4, L..info_string3 # DW_AT_name
+; CHECK-NEXT: .byte 1 # DW_AT_decl_file
+; CHECK-NEXT: .byte 1 # DW_AT_decl_line
+; CHECK-NEXT: .vbyte 4, 82 # DW_AT_type
+; CHECK-NEXT: .byte 1 # DW_AT_external
+; CHECK-NEXT: .byte 2 # Abbrev [2] 0x3c:0x16 DW_TAG_subprogram
+; CHECK-NEXT: .vbyte 4, L..func_begin1 # DW_AT_low_pc
+; CHECK-NEXT: .vbyte 4, L..func_end1 # DW_AT_high_pc
+; CHECK-NEXT: .byte 1 # DW_AT_frame_base
+; CHECK-NEXT: .byte 81
+; CHECK-NEXT: .vbyte 4, L..info_string5 # DW_AT_name
+; CHECK-NEXT: .byte 1 # DW_AT_decl_file
+; CHECK-NEXT: .byte 2 # DW_AT_decl_line
+; CHECK-NEXT: .vbyte 4, 82 # DW_AT_type
+; CHECK-NEXT: .byte 1 # DW_AT_external
+; CHECK-NEXT: .byte 3 # Abbrev [3] 0x52:0x7 DW_TAG_base_type
+; CHECK-NEXT: .vbyte 4, L..info_string4 # DW_AT_name
+; CHECK-NEXT: .byte 5 # DW_AT_encoding
+; CHECK-NEXT: .byte 4 # DW_AT_byte_size
+; CHECK-NEXT: .byte 0 # End Of Children Mark
+; CHECK-NEXT: L..debug_info_end0:
+; CHECK: .dwsect 0x80000
+; CHECK-NEXT: L...dwrnges:
+; CHECK-NEXT: L..debug_ranges0:
+; CHECK-NEXT: .vbyte 4, L..func_begin0
+; CHECK-NEXT: .vbyte 4, L..func_end0
+; CHECK-NEXT: .vbyte 4, L..func_begin1
+; CHECK-NEXT: .vbyte 4, L..func_end1
+; CHECK-NEXT: .vbyte 4, 0
+; CHECK-NEXT: .vbyte 4, 0
+; CHECK: .dwsect 0x70000
+; CHECK-NEXT: L...dwstr:
+; CHECK-NEXT: L..info_string0:
+; CHECK-NEXT: .byte 'c,'l,'a,'n,'g,' ,'v,'e,'r,'s,'i,'o,'n,' ,'1,'3,'.,'0,'.,'0,0000 # string offset=0
+; CHECK-NEXT: L..info_string1:
+; CHECK-NEXT: .byte '2,'.,'c,0000 # string offset=21
+; CHECK-NEXT: L..info_string2:
+; CHECK-NEXT: .byte 'd,'e,'b,'u,'g,0000 # string offset=25
+; CHECK-NEXT: L..info_string3:
+; CHECK-NEXT: .byte 'b,'a,'r,0000 # string offset=31
+; CHECK-NEXT: L..info_string4:
+; CHECK-NEXT: .byte 'i,'n,'t,0000 # string offset=35
+; CHECK-NEXT: L..info_string5:
+; CHECK-NEXT: .byte 'm,'a,'i,'n,0000 # string offset=39
+; CHECK-NEXT: .toc
+; CHECK: .dwsect 0x20000
+; CHECK-NEXT: L...dwline:
+; CHECK-NEXT: L..debug_line_0:
+; CHECK-NEXT: .set L..line_table_start0, L..debug_line_0-4
+; CHECK-NEXT: .vbyte 2, 3
+; CHECK-NEXT: .vbyte 4, L..tmp9-L..tmp8
+; CHECK-NEXT: L..tmp8:
+; CHECK-NEXT: .byte 4
+; CHECK-NEXT: .byte 1
+; CHECK-NEXT: .byte -5
+; CHECK-NEXT: .byte 14
+; CHECK-NEXT: .byte 13
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 1
+; CHECK-NEXT: .byte 1
+; CHECK-NEXT: .byte 1
+; CHECK-NEXT: .byte 1
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 1
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 1
+; CHECK-NEXT: .byte 'd,'e,'b,'u,'g
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte '2,'.,'c
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 1
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: L..tmp9:
+; CHECK-NEXT: .byte 0 # Set address to L..tmp0
+; CHECK-NEXT: .byte 5
+; CHECK-NEXT: .byte 2
+; CHECK-NEXT: .vbyte 4, L..tmp0
+; CHECK-NEXT: .byte 1 # Start sequence
+; CHECK-NEXT: .byte 5
+; CHECK-NEXT: .byte 12
+; CHECK-NEXT: .byte 10
+; CHECK-NEXT: .byte 0 # Set address to L..tmp1
+; CHECK-NEXT: .byte 5
+; CHECK-NEXT: .byte 2
+; CHECK-NEXT: .vbyte 4, L..tmp1
+; CHECK-NEXT: .byte 3 # Advance line 0
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 1
+; CHECK-NEXT: .byte 0 # Set address to L..sec_end0
+; CHECK-NEXT: .byte 5
+; CHECK-NEXT: .byte 2
+; CHECK-NEXT: .vbyte 4, L..sec_end0
+; CHECK-NEXT: .byte 0 # End sequence
+; CHECK-NEXT: .byte 1
+; CHECK-NEXT: .byte 1
+; CHECK-NEXT: .byte 0 # Set address to L..tmp3
+; CHECK-NEXT: .byte 5
+; CHECK-NEXT: .byte 2
+; CHECK-NEXT: .vbyte 4, L..tmp3
+; CHECK-NEXT: .byte 19 # Start sequence
+; CHECK-NEXT: .byte 5
+; CHECK-NEXT: .byte 10
+; CHECK-NEXT: .byte 10
+; CHECK-NEXT: .byte 0 # Set address to L..tmp5
+; CHECK-NEXT: .byte 5
+; CHECK-NEXT: .byte 2
+; CHECK-NEXT: .vbyte 4, L..tmp5
+; CHECK-NEXT: .byte 3 # Advance line 1
+; CHECK-NEXT: .byte 1
+; CHECK-NEXT: .byte 1
+; CHECK-NEXT: .byte 5
+; CHECK-NEXT: .byte 3
+; CHECK-NEXT: .byte 6
+; CHECK-NEXT: .byte 0 # Set address to L..tmp6
+; CHECK-NEXT: .byte 5
+; CHECK-NEXT: .byte 2
+; CHECK-NEXT: .vbyte 4, L..tmp6
+; CHECK-NEXT: .byte 3 # Advance line 0
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 1
+; CHECK-NEXT: .byte 0 # Set address to L..sec_end0
+; CHECK-NEXT: .byte 5
+; CHECK-NEXT: .byte 2
+; CHECK-NEXT: .vbyte 4, L..sec_end0
+; CHECK-NEXT: .byte 0 # End sequence
+; CHECK-NEXT: .byte 1
+; CHECK-NEXT: .byte 1
+; CHECK-NEXT: L..debug_line_end0:
diff --git a/llvm/test/DebugInfo/XCOFF/function-sections.ll b/llvm/test/DebugInfo/XCOFF/function-sections.ll
new file mode 100644
index 000000000000..7e5f983c4967
--- /dev/null
+++ b/llvm/test/DebugInfo/XCOFF/function-sections.ll
@@ -0,0 +1,315 @@
+
+; RUN: llc -mtriple powerpc-ibm-aix-xcoff -function-sections \
+; RUN: < %s | FileCheck %s
+
+source_filename = "1.c"
+target datalayout = "E-m:a-p:32:32-i64:64-n32"
+
+; Function Attrs: noinline nounwind optnone
+define i32 @foo() #0 !dbg !8 {
+entry:
+ ret i32 0, !dbg !12
+}
+
+; Function Attrs: noinline nounwind optnone
+define i32 @bar() #0 !dbg !13 {
+entry:
+ ret i32 1, !dbg !14
+}
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3, !4, !5, !6}
+!llvm.ident = !{!7}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 13.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None)
+!1 = !DIFile(filename: "1.c", directory: "debug")
+!2 = !{}
+!3 = !{i32 7, !"Dwarf Version", i32 3}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = !{i32 1, !"wchar_size", i32 2}
+!6 = !{i32 7, !"PIC Level", i32 2}
+!7 = !{!"clang version 13.0.0"}
+!8 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 1, type: !9, scopeLine: 2, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2)
+!9 = !DISubroutineType(types: !10)
+!10 = !{!11}
+!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!12 = !DILocation(line: 3, column: 3, scope: !8)
+!13 = distinct !DISubprogram(name: "bar", scope: !1, file: !1, line: 6, type: !9, scopeLine: 7, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2)
+!14 = !DILocation(line: 8, column: 3, scope: !13)
+
+; CHECK: .csect .text[PR],2
+; CHECK-NEXT: .file "1.c"
+; CHECK-NEXT: .csect .foo[PR],2
+; CHECK-NEXT: .globl foo[DS] # -- Begin function foo
+; CHECK-NEXT: .globl .foo[PR]
+; CHECK-NEXT: .align 2
+; CHECK-NEXT: .csect foo[DS],2
+; CHECK-NEXT: .vbyte 4, .foo[PR] # @foo
+; CHECK-NEXT: .vbyte 4, TOC[TC0]
+; CHECK-NEXT: .vbyte 4, 0
+; CHECK-NEXT: .csect .foo[PR],2
+; CHECK-NEXT: L..func_begin0:
+; CHECK-NEXT: # %bb.0: # %entry
+; CHECK-NEXT: L..tmp0:
+; CHECK-NEXT: L..tmp1:
+; CHECK-NEXT: li 3, 0
+; CHECK-NEXT: blr
+; CHECK-NEXT: L..tmp2:
+; CHECK-NEXT: L..foo0:
+; CHECK-NEXT: .vbyte 4, 0x00000000 # Traceback table begin
+; CHECK-NEXT: .byte 0x00 # Version = 0
+; CHECK-NEXT: .byte 0x09 # Language = CPlusPlus
+; CHECK-NEXT: .byte 0x20 # -IsGlobaLinkage, -IsOutOfLineEpilogOrPrologue
+; CHECK-NEXT: # +HasTraceBackTableOffset, -IsInternalProcedure
+; CHECK-NEXT: # -HasControlledStorage, -IsTOCless
+; CHECK-NEXT: # -IsFloatingPointPresent
+; CHECK-NEXT: # -IsFloatingPointOperationLogOrAbortEnabled
+; CHECK-NEXT: .byte 0x40 # -IsInterruptHandler, +IsFunctionNamePresent, -IsAllocaUsed
+; CHECK-NEXT: # OnConditionDirective = 0, -IsCRSaved, -IsLRSaved
+; CHECK-NEXT: .byte 0x80 # +IsBackChainStored, -IsFixup, NumOfFPRsSaved = 0
+; CHECK-NEXT: .byte 0x00 # -HasVectorInfo, -HasExtensionTable, NumOfGPRsSaved = 0
+; CHECK-NEXT: .byte 0x00 # NumberOfFixedParms = 0
+; CHECK-NEXT: .byte 0x01 # NumberOfFPParms = 0, +HasParmsOnStack
+; CHECK-NEXT: .vbyte 4, L..foo0-.foo[PR] # Function size
+; CHECK-NEXT: .vbyte 2, 0x0003 # Function name len = 3
+; CHECK-NEXT: .byte 'f,'o,'o # Function Name
+; CHECK-NEXT: L..func_end0:
+; CHECK-NEXT: # -- End function
+; CHECK-NEXT: .csect .bar[PR],2
+; CHECK-NEXT: .globl bar[DS] # -- Begin function bar
+; CHECK-NEXT: .globl .bar[PR]
+; CHECK-NEXT: .align 2
+; CHECK-NEXT: .csect bar[DS],2
+; CHECK-NEXT: .vbyte 4, .bar[PR] # @bar
+; CHECK-NEXT: .vbyte 4, TOC[TC0]
+; CHECK-NEXT: .vbyte 4, 0
+; CHECK-NEXT: .csect .bar[PR],2
+; CHECK-NEXT: L..func_begin1:
+; CHECK-NEXT: # %bb.0: # %entry
+; CHECK-NEXT: L..tmp3:
+; CHECK-NEXT: L..tmp4:
+; CHECK-NEXT: li 3, 1
+; CHECK-NEXT: blr
+; CHECK-NEXT: L..tmp5:
+; CHECK-NEXT: L..bar0:
+; CHECK-NEXT: .vbyte 4, 0x00000000 # Traceback table begin
+; CHECK-NEXT: .byte 0x00 # Version = 0
+; CHECK-NEXT: .byte 0x09 # Language = CPlusPlus
+; CHECK-NEXT: .byte 0x20 # -IsGlobaLinkage, -IsOutOfLineEpilogOrPrologue
+; CHECK-NEXT: # +HasTraceBackTableOffset, -IsInternalProcedure
+; CHECK-NEXT: # -HasControlledStorage, -IsTOCless
+; CHECK-NEXT: # -IsFloatingPointPresent
+; CHECK-NEXT: # -IsFloatingPointOperationLogOrAbortEnabled
+; CHECK-NEXT: .byte 0x40 # -IsInterruptHandler, +IsFunctionNamePresent, -IsAllocaUsed
+; CHECK-NEXT: # OnConditionDirective = 0, -IsCRSaved, -IsLRSaved
+; CHECK-NEXT: .byte 0x80 # +IsBackChainStored, -IsFixup, NumOfFPRsSaved = 0
+; CHECK-NEXT: .byte 0x00 # -HasVectorInfo, -HasExtensionTable, NumOfGPRsSaved = 0
+; CHECK-NEXT: .byte 0x00 # NumberOfFixedParms = 0
+; CHECK-NEXT: .byte 0x01 # NumberOfFPParms = 0, +HasParmsOnStack
+; CHECK-NEXT: .vbyte 4, L..bar0-.bar[PR] # Function size
+; CHECK-NEXT: .vbyte 2, 0x0003 # Function name len = 3
+; CHECK-NEXT: .byte 'b,'a,'r # Function Name
+; CHECK-NEXT: L..func_end1:
+; CHECK-NEXT: # -- End function
+; CHECK-NEXT: L..sec_end0:
+; CHECK: .dwsect 0x60000
+; CHECK-NEXT: L...dwabrev:
+; CHECK-NEXT: .byte 1 # Abbreviation Code
+; CHECK-NEXT: .byte 17 # DW_TAG_compile_unit
+; CHECK-NEXT: .byte 1 # DW_CHILDREN_yes
+; CHECK-NEXT: .byte 37 # DW_AT_producer
+; CHECK-NEXT: .byte 14 # DW_FORM_strp
+; CHECK-NEXT: .byte 19 # DW_AT_language
+; CHECK-NEXT: .byte 5 # DW_FORM_data2
+; CHECK-NEXT: .byte 3 # DW_AT_name
+; CHECK-NEXT: .byte 14 # DW_FORM_strp
+; CHECK-NEXT: .byte 16 # DW_AT_stmt_list
+; CHECK-NEXT: .byte 6 # DW_FORM_data4
+; CHECK-NEXT: .byte 27 # DW_AT_comp_dir
+; CHECK-NEXT: .byte 14 # DW_FORM_strp
+; CHECK-NEXT: .byte 17 # DW_AT_low_pc
+; CHECK-NEXT: .byte 1 # DW_FORM_addr
+; CHECK-NEXT: .byte 85 # DW_AT_ranges
+; CHECK-NEXT: .byte 6 # DW_FORM_data4
+; CHECK-NEXT: .byte 0 # EOM(1)
+; CHECK-NEXT: .byte 0 # EOM(2)
+; CHECK-NEXT: .byte 2 # Abbreviation Code
+; CHECK-NEXT: .byte 46 # DW_TAG_subprogram
+; CHECK-NEXT: .byte 0 # DW_CHILDREN_no
+; CHECK-NEXT: .byte 17 # DW_AT_low_pc
+; CHECK-NEXT: .byte 1 # DW_FORM_addr
+; CHECK-NEXT: .byte 18 # DW_AT_high_pc
+; CHECK-NEXT: .byte 1 # DW_FORM_addr
+; CHECK-NEXT: .byte 64 # DW_AT_frame_base
+; CHECK-NEXT: .byte 10 # DW_FORM_block1
+; CHECK-NEXT: .byte 3 # DW_AT_name
+; CHECK-NEXT: .byte 14 # DW_FORM_strp
+; CHECK-NEXT: .byte 58 # DW_AT_decl_file
+; CHECK-NEXT: .byte 11 # DW_FORM_data1
+; CHECK-NEXT: .byte 59 # DW_AT_decl_line
+; CHECK-NEXT: .byte 11 # DW_FORM_data1
+; CHECK-NEXT: .byte 39 # DW_AT_prototyped
+; CHECK-NEXT: .byte 12 # DW_FORM_flag
+; CHECK-NEXT: .byte 73 # DW_AT_type
+; CHECK-NEXT: .byte 19 # DW_FORM_ref4
+; CHECK-NEXT: .byte 63 # DW_AT_external
+; CHECK-NEXT: .byte 12 # DW_FORM_flag
+; CHECK-NEXT: .byte 0 # EOM(1)
+; CHECK-NEXT: .byte 0 # EOM(2)
+; CHECK-NEXT: .byte 3 # Abbreviation Code
+; CHECK-NEXT: .byte 36 # DW_TAG_base_type
+; CHECK-NEXT: .byte 0 # DW_CHILDREN_no
+; CHECK-NEXT: .byte 3 # DW_AT_name
+; CHECK-NEXT: .byte 14 # DW_FORM_strp
+; CHECK-NEXT: .byte 62 # DW_AT_encoding
+; CHECK-NEXT: .byte 11 # DW_FORM_data1
+; CHECK-NEXT: .byte 11 # DW_AT_byte_size
+; CHECK-NEXT: .byte 11 # DW_FORM_data1
+; CHECK-NEXT: .byte 0 # EOM(1)
+; CHECK-NEXT: .byte 0 # EOM(2)
+; CHECK-NEXT: .byte 0 # EOM(3)
+; CHECK: .dwsect 0x10000
+; CHECK-NEXT: L...dwinfo:
+; CHECK-NEXT: L..cu_begin0:
+; CHECK-NEXT: .vbyte 2, 3 # DWARF version number
+; CHECK-NEXT: .vbyte 4, L...dwabrev # Offset Into Abbrev. Section
+; CHECK-NEXT: .byte 4 # Address Size (in bytes)
+; CHECK-NEXT: .byte 1 # Abbrev [1] 0xb:0x51 DW_TAG_compile_unit
+; CHECK-NEXT: .vbyte 4, L..info_string0 # DW_AT_producer
+; CHECK-NEXT: .vbyte 2, 12 # DW_AT_language
+; CHECK-NEXT: .vbyte 4, L..info_string1 # DW_AT_name
+; CHECK-NEXT: .vbyte 4, L..line_table_start0 # DW_AT_stmt_list
+; CHECK-NEXT: .vbyte 4, L..info_string2 # DW_AT_comp_dir
+; CHECK-NEXT: .vbyte 4, 0 # DW_AT_low_pc
+; CHECK-NEXT: .vbyte 4, L..debug_ranges0 # DW_AT_ranges
+; CHECK-NEXT: .byte 2 # Abbrev [2] 0x26:0x17 DW_TAG_subprogram
+; CHECK-NEXT: .vbyte 4, L..func_begin0 # DW_AT_low_pc
+; CHECK-NEXT: .vbyte 4, L..func_end0 # DW_AT_high_pc
+; CHECK-NEXT: .byte 1 # DW_AT_frame_base
+; CHECK-NEXT: .byte 81
+; CHECK-NEXT: .vbyte 4, L..info_string3 # DW_AT_name
+; CHECK-NEXT: .byte 1 # DW_AT_decl_file
+; CHECK-NEXT: .byte 1 # DW_AT_decl_line
+; CHECK-NEXT: .byte 1 # DW_AT_prototyped
+; CHECK-NEXT: .vbyte 4, 84 # DW_AT_type
+; CHECK-NEXT: .byte 1 # DW_AT_external
+; CHECK-NEXT: .byte 2 # Abbrev [2] 0x3d:0x17 DW_TAG_subprogram
+; CHECK-NEXT: .vbyte 4, L..func_begin1 # DW_AT_low_pc
+; CHECK-NEXT: .vbyte 4, L..func_end1 # DW_AT_high_pc
+; CHECK-NEXT: .byte 1 # DW_AT_frame_base
+; CHECK-NEXT: .byte 81
+; CHECK-NEXT: .vbyte 4, L..info_string5 # DW_AT_name
+; CHECK-NEXT: .byte 1 # DW_AT_decl_file
+; CHECK-NEXT: .byte 6 # DW_AT_decl_line
+; CHECK-NEXT: .byte 1 # DW_AT_prototyped
+; CHECK-NEXT: .vbyte 4, 84 # DW_AT_type
+; CHECK-NEXT: .byte 1 # DW_AT_external
+; CHECK-NEXT: .byte 3 # Abbrev [3] 0x54:0x7 DW_TAG_base_type
+; CHECK-NEXT: .vbyte 4, L..info_string4 # DW_AT_name
+; CHECK-NEXT: .byte 5 # DW_AT_encoding
+; CHECK-NEXT: .byte 4 # DW_AT_byte_size
+; CHECK-NEXT: .byte 0 # End Of Children Mark
+; CHECK-NEXT: L..debug_info_end0:
+; CHECK: .dwsect 0x80000
+; CHECK-NEXT: L...dwrnges:
+; CHECK-NEXT: L..debug_ranges0:
+; CHECK-NEXT: .vbyte 4, L..func_begin0
+; CHECK-NEXT: .vbyte 4, L..func_end0
+; CHECK-NEXT: .vbyte 4, L..func_begin1
+; CHECK-NEXT: .vbyte 4, L..func_end1
+; CHECK-NEXT: .vbyte 4, 0
+; CHECK-NEXT: .vbyte 4, 0
+; CHECK: .dwsect 0x70000
+; CHECK-NEXT: L...dwstr:
+; CHECK-NEXT: L..info_string0:
+; CHECK-NEXT: .byte 'c,'l,'a,'n,'g,' ,'v,'e,'r,'s,'i,'o,'n,' ,'1,'3,'.,'0,'.,'0,0000 # string offset=0
+; CHECK-NEXT: L..info_string1:
+; CHECK-NEXT: .byte '1,'.,'c,0000 # string offset=21
+; CHECK-NEXT: L..info_string2:
+; CHECK-NEXT: .byte 'd,'e,'b,'u,'g,0000 # string offset=25
+; CHECK-NEXT: L..info_string3:
+; CHECK-NEXT: .byte 'f,'o,'o,0000 # string offset=31
+; CHECK-NEXT: L..info_string4:
+; CHECK-NEXT: .byte 'i,'n,'t,0000 # string offset=35
+; CHECK-NEXT: L..info_string5:
+; CHECK-NEXT: .byte 'b,'a,'r,0000 # string offset=39
+; CHECK-NEXT: .toc
+; CHECK: .dwsect 0x20000
+; CHECK-NEXT: L...dwline:
+; CHECK-NEXT: L..debug_line_0:
+; CHECK-NEXT: .set L..line_table_start0, L..debug_line_0-4
+; CHECK-NEXT: .vbyte 2, 3
+; CHECK-NEXT: .vbyte 4, L..tmp7-L..tmp6
+; CHECK-NEXT: L..tmp6:
+; CHECK-NEXT: .byte 4
+; CHECK-NEXT: .byte 1
+; CHECK-NEXT: .byte -5
+; CHECK-NEXT: .byte 14
+; CHECK-NEXT: .byte 13
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 1
+; CHECK-NEXT: .byte 1
+; CHECK-NEXT: .byte 1
+; CHECK-NEXT: .byte 1
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 1
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 1
+; CHECK-NEXT: .byte 'd,'e,'b,'u,'g
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte '1,'.,'c
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 1
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: .byte 0
+; CHECK-NEXT: L..tmp7:
+; CHECK-NEXT: .byte 0 # Set address to L..tmp0
+; CHECK-NEXT: .byte 5
+; CHECK-NEXT: .byte 2
+; CHECK-NEXT: .vbyte 4, L..tmp0
+; CHECK-NEXT: .byte 19 # Start sequence
+; CHECK-NEXT: .byte 5
+; CHECK-NEXT: .byte 3
+; CHECK-NEXT: .byte 10
+; CHECK-NEXT: .byte 0 # Set address to L..tmp1
+; CHECK-NEXT: .byte 5
+; CHECK-NEXT: .byte 2
+; CHECK-NEXT: .vbyte 4, L..tmp1
+; CHECK-NEXT: .byte 3 # Advance line 1
+; CHECK-NEXT: .byte 1
+; CHECK-NEXT: .byte 1
+; CHECK-NEXT: .byte 0 # Set address to L..sec_end0
+; CHECK-NEXT: .byte 5
+; CHECK-NEXT: .byte 2
+; CHECK-NEXT: .vbyte 4, L..sec_end0
+; CHECK-NEXT: .byte 0 # End sequence
+; CHECK-NEXT: .byte 1
+; CHECK-NEXT: .byte 1
+; CHECK-NEXT: .byte 0 # Set address to L..tmp3
+; CHECK-NEXT: .byte 5
+; CHECK-NEXT: .byte 2
+; CHECK-NEXT: .vbyte 4, L..tmp3
+; CHECK-NEXT: .byte 24 # Start sequence
+; CHECK-NEXT: .byte 5
+; CHECK-NEXT: .byte 3
+; CHECK-NEXT: .byte 10
+; CHECK-NEXT: .byte 0 # Set address to L..tmp4
+; CHECK-NEXT: .byte 5
+; CHECK-NEXT: .byte 2
+; CHECK-NEXT: .vbyte 4, L..tmp4
+; CHECK-NEXT: .byte 3 # Advance line 1
+; CHECK-NEXT: .byte 1
+; CHECK-NEXT: .byte 1
+; CHECK-NEXT: .byte 0 # Set address to L..sec_end0
+; CHECK-NEXT: .byte 5
+; CHECK-NEXT: .byte 2
+; CHECK-NEXT: .vbyte 4, L..sec_end0
+; CHECK-NEXT: .byte 0 # End sequence
+; CHECK-NEXT: .byte 1
+; CHECK-NEXT: .byte 1
+; CHECK-NEXT: L..debug_line_end0:
diff --git a/llvm/test/DebugInfo/XCOFF/lit.local.cfg b/llvm/test/DebugInfo/XCOFF/lit.local.cfg
new file mode 100644
index 000000000000..091332439b18
--- /dev/null
+++ b/llvm/test/DebugInfo/XCOFF/lit.local.cfg
@@ -0,0 +1,2 @@
+if not 'PowerPC' in config.root.targets:
+ config.unsupported = True
More information about the llvm-commits
mailing list