diff --git a/llvm/include/llvm/MC/MCObjectWriter.h b/llvm/include/llvm/MC/MCObjectWriter.h --- a/llvm/include/llvm/MC/MCObjectWriter.h +++ b/llvm/include/llvm/MC/MCObjectWriter.h @@ -110,6 +110,12 @@ unsigned FunctionSize, bool hasDebug) { report_fatal_error("addExceptionEntry is only supported on XCOFF targets"); } + + virtual void recordRefSymbol(const MCSymbol *Symbol, + const MCFragment *Fragment) { + report_fatal_error("recordRefSymbol is only supported on XCOFF targets"); + } + /// Write the object file and returns the number of bytes written. /// /// This routine is called by the assembler after layout and relaxation is diff --git a/llvm/include/llvm/MC/MCStreamer.h b/llvm/include/llvm/MC/MCStreamer.h --- a/llvm/include/llvm/MC/MCStreamer.h +++ b/llvm/include/llvm/MC/MCStreamer.h @@ -641,7 +641,7 @@ /// relocation table for one or more symbols. /// /// \param Sym - The symbol on the .ref directive. - virtual void emitXCOFFRefDirective(StringRef Sym); + virtual void emitXCOFFRefDirective(const MCSymbol *Symbol); virtual void emitXCOFFInfoDirective(StringRef Name, const SmallVector &Metadata); diff --git a/llvm/include/llvm/MC/MCXCOFFStreamer.h b/llvm/include/llvm/MC/MCXCOFFStreamer.h --- a/llvm/include/llvm/MC/MCXCOFFStreamer.h +++ b/llvm/include/llvm/MC/MCXCOFFStreamer.h @@ -31,10 +31,7 @@ void emitXCOFFSymbolLinkageWithVisibility(MCSymbol *Symbol, MCSymbolAttr Linkage, MCSymbolAttr Visibility) override; - void emitXCOFFRefDirective(StringRef Name) override { - report_fatal_error("emitXCOFFRefDirective is not implemented yet on object" - "generation path"); - } + void emitXCOFFRefDirective(const MCSymbol *Symbol) override; void emitXCOFFRenameDirective(const MCSymbol *Name, StringRef Rename) override { report_fatal_error("emitXCOFFRenameDirective is not implemented yet on " diff --git a/llvm/lib/MC/MCAsmStreamer.cpp b/llvm/lib/MC/MCAsmStreamer.cpp --- a/llvm/lib/MC/MCAsmStreamer.cpp +++ b/llvm/lib/MC/MCAsmStreamer.cpp @@ -195,7 +195,7 @@ void emitXCOFFRenameDirective(const MCSymbol *Name, StringRef Rename) override; - void emitXCOFFRefDirective(StringRef Name) override; + void emitXCOFFRefDirective(const MCSymbol *Symbol) override; void emitXCOFFInfoDirective(StringRef Name, const SmallVector &Metadata) override; @@ -947,8 +947,9 @@ EmitEOL(); } -void MCAsmStreamer::emitXCOFFRefDirective(StringRef Name) { - OS << "\t.ref " << Name; +void MCAsmStreamer::emitXCOFFRefDirective(const MCSymbol *Symbol) { + OS << "\t.ref "; + Symbol->print(OS, MAI); EmitEOL(); } diff --git a/llvm/lib/MC/MCStreamer.cpp b/llvm/lib/MC/MCStreamer.cpp --- a/llvm/lib/MC/MCStreamer.cpp +++ b/llvm/lib/MC/MCStreamer.cpp @@ -1187,7 +1187,7 @@ "XCOFF targets"); } -void MCStreamer::emitXCOFFRefDirective(StringRef Name) { +void MCStreamer::emitXCOFFRefDirective(const MCSymbol *Symbol) { llvm_unreachable("emitXCOFFRefDirective is only supported on XCOFF targets"); } diff --git a/llvm/lib/MC/MCXCOFFStreamer.cpp b/llvm/lib/MC/MCXCOFFStreamer.cpp --- a/llvm/lib/MC/MCXCOFFStreamer.cpp +++ b/llvm/lib/MC/MCXCOFFStreamer.cpp @@ -81,6 +81,13 @@ emitSymbolAttribute(Symbol, Visibility); } +void MCXCOFFStreamer::emitXCOFFRefDirective(const MCSymbol *Symbol) { + // A R_REF relocation will be recorded later to prevent garbage collection (by + // the binder) of the ref symbol. + MCDataFragment *DF = getOrCreateDataFragment(); + getAssembler().getWriter().recordRefSymbol(Symbol, DF); +} + void MCXCOFFStreamer::emitXCOFFExceptDirective(const MCSymbol *Symbol, const MCSymbol *Trap, unsigned Lang, unsigned Reason, diff --git a/llvm/lib/MC/XCOFFObjectWriter.cpp b/llvm/lib/MC/XCOFFObjectWriter.cpp --- a/llvm/lib/MC/XCOFFObjectWriter.cpp +++ b/llvm/lib/MC/XCOFFObjectWriter.cpp @@ -287,6 +287,8 @@ ExceptionSectionEntry ExceptionSection; + std::vector> RefSymbolInfo; + CsectGroup &getCsectGroup(const MCSectionXCOFF *MCSec); void reset() override; @@ -296,6 +298,11 @@ void recordRelocation(MCAssembler &, const MCAsmLayout &, const MCFragment *, const MCFixup &, MCValue, uint64_t &) override; + void recordRefSymbol(const MCSymbol *Symbol, + const MCFragment *Fragment) override; + + void recordRelocationForRef(const MCAsmLayout &Layout); + uint64_t writeObject(MCAssembler &, const MCAsmLayout &) override; bool is64Bit() const { return TargetObjectWriter->is64Bit(); } @@ -572,21 +579,22 @@ assignAddressesAndIndices(Layout); } +static uint32_t +getSymbolIndex(DenseMap SymbolIndexMap, + const MCSymbol *Sym, const MCSectionXCOFF *ContainingCsect) { + // If we could not find the symbol directly in SymbolIndexMap, this symbol + // could either be a temporary symbol or an undefined symbol. In this case, + // we would need to have the relocation reference its csect instead. + return SymbolIndexMap.find(Sym) != SymbolIndexMap.end() + ? SymbolIndexMap[Sym] + : SymbolIndexMap[ContainingCsect->getQualNameSymbol()]; +} + void XCOFFObjectWriter::recordRelocation(MCAssembler &Asm, const MCAsmLayout &Layout, const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target, uint64_t &FixedValue) { - auto getIndex = [this](const MCSymbol *Sym, - const MCSectionXCOFF *ContainingCsect) { - // If we could not find the symbol directly in SymbolIndexMap, this symbol - // could either be a temporary symbol or an undefined symbol. In this case, - // we would need to have the relocation reference its csect instead. - return SymbolIndexMap.find(Sym) != SymbolIndexMap.end() - ? SymbolIndexMap[Sym] - : SymbolIndexMap[ContainingCsect->getQualNameSymbol()]; - }; - auto getVirtualAddress = [this, &Layout](const MCSymbol *Sym, const MCSectionXCOFF *ContainingSect) -> uint64_t { @@ -622,7 +630,7 @@ assert(SectionMap.find(SymASec) != SectionMap.end() && "Expected containing csect to exist in map."); - const uint32_t Index = getIndex(SymA, SymASec); + const uint32_t Index = getSymbolIndex(SymbolIndexMap, SymA, SymASec); if (Type == XCOFF::RelocationType::R_POS || Type == XCOFF::RelocationType::R_TLS) // The FixedValue should be symbol's virtual address in this object file @@ -689,7 +697,7 @@ assert(Type == XCOFF::RelocationType::R_POS && "SymA must be R_POS here if it's not opposite term or paired " "relocatable term."); - const uint32_t IndexB = getIndex(SymB, SymBSec); + const uint32_t IndexB = getSymbolIndex(SymbolIndexMap, SymB, SymBSec); // SymB must be R_NEG here, given the general form of Target(MCValue) is // "SymbolA - SymbolB + imm64". const uint8_t TypeB = XCOFF::RelocationType::R_NEG; @@ -1398,6 +1406,31 @@ } SymbolTableEntryCount = SymbolTableIndex; + + recordRelocationForRef(Layout); +} + +void XCOFFObjectWriter::recordRelocationForRef(const MCAsmLayout &Layout) { + for (auto RefSymbol : RefSymbolInfo) { + auto Symbol = RefSymbol.first; + auto Fragment = RefSymbol.second; + const MCSectionXCOFF *SymSec = + getContainingCsect(cast(Symbol)); + assert(SectionMap.find(SymSec) != SectionMap.end() && + "Expected containing csect to exist in map."); + const uint32_t Index = getSymbolIndex(SymbolIndexMap, Symbol, SymSec); + MCSectionXCOFF *RelocationSec = cast(Fragment->getParent()); + XCOFFRelocation Reloc = { + Index, static_cast(Layout.getFragmentOffset(Fragment)), 0, + XCOFF::R_REF}; + SectionMap[RelocationSec]->Relocations.push_back(Reloc); + } +} + +void XCOFFObjectWriter::recordRefSymbol(const MCSymbol *Symbol, + const MCFragment *Fragment) { + RefSymbolInfo.push_back( + std::pair(Symbol, Fragment)); } void XCOFFObjectWriter::writeSectionForControlSectionEntry( diff --git a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp --- a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp +++ b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp @@ -2586,16 +2586,22 @@ OutStreamer->switchSection(CntsSection); if (OutContext.hasXCOFFSection( "__llvm_prf_data", - XCOFF::CsectProperties(XCOFF::XMC_RW, XCOFF::XTY_SD))) - OutStreamer->emitXCOFFRefDirective("__llvm_prf_data[RW]"); + XCOFF::CsectProperties(XCOFF::XMC_RW, XCOFF::XTY_SD))) { + MCSymbol *S = OutContext.getOrCreateSymbol("__llvm_prf_data[RW]"); + OutStreamer->emitXCOFFRefDirective(S); + } if (OutContext.hasXCOFFSection( "__llvm_prf_names", - XCOFF::CsectProperties(XCOFF::XMC_RO, XCOFF::XTY_SD))) - OutStreamer->emitXCOFFRefDirective("__llvm_prf_names[RO]"); + XCOFF::CsectProperties(XCOFF::XMC_RO, XCOFF::XTY_SD))) { + MCSymbol *S = OutContext.getOrCreateSymbol("__llvm_prf_names[RO]"); + OutStreamer->emitXCOFFRefDirective(S); + } if (OutContext.hasXCOFFSection( "__llvm_prf_vnds", - XCOFF::CsectProperties(XCOFF::XMC_RW, XCOFF::XTY_SD))) - OutStreamer->emitXCOFFRefDirective("__llvm_prf_vnds[RW]"); + XCOFF::CsectProperties(XCOFF::XMC_RW, XCOFF::XTY_SD))) { + MCSymbol *S = OutContext.getOrCreateSymbol("__llvm_prf_vnds[RW]"); + OutStreamer->emitXCOFFRefDirective(S); + } } } diff --git a/llvm/test/CodeGen/PowerPC/pgo-ref-directive.ll b/llvm/test/CodeGen/PowerPC/pgo-ref-directive.ll --- a/llvm/test/CodeGen/PowerPC/pgo-ref-directive.ll +++ b/llvm/test/CodeGen/PowerPC/pgo-ref-directive.ll @@ -4,6 +4,9 @@ ; RUN: llc -verify-machineinstrs -mcpu=pwr4 -mattr=-altivec -mtriple powerpc-ibm-aix-xcoff -xcoff-traceback-table=false < %t/no-vnds.ll | FileCheck %s --check-prefixes=NOVNDS ; RUN: llc -verify-machineinstrs -mcpu=pwr4 -mattr=-altivec -mtriple powerpc-ibm-aix-xcoff -xcoff-traceback-table=false < %t/with-vnds.ll | FileCheck %s --check-prefixes=WITHVNDS +; RUN: llc -verify-machineinstrs -mcpu=pwr4 -mattr=-altivec -mtriple powerpc-ibm-aix-xcoff \ +; RUN: -xcoff-traceback-table=false --filetype=obj < %t/with-vnds.ll -o %t/with-vnds.o +; RUN: llvm-objdump %t/with-vnds.o -tr | FileCheck %s --check-prefix=OBJ ;--- no-ref.ll ; The absence of a __llvm_prf_cnts section should stop generating the .refs. @@ -80,3 +83,22 @@ ; WITHVNDS-NEXT: .ref __llvm_prf_data[RW] ; WITHVNDS-NEXT: .ref __llvm_prf_names[RO] ; WITHVNDS-NEXT: .ref __llvm_prf_vnds[RW] + +; OBJ: SYMBOL TABLE: +; OBJ-NEXT: 00000000 df *DEBUG* 00000000 +; OBJ-NEXT: 00000000 l .text 00000008 .text +; OBJ-NEXT: 00000000 g F .text (csect: .text) 00000000 .main +; OBJ-NEXT: 00000008 l .text 00000006 __llvm_prf_names +; OBJ-NEXT: 00000010 l O .data 00000008 __llvm_prf_cnts +; OBJ-NEXT: 00000018 l O .data 00000008 __llvm_prf_data +; OBJ-NEXT: 00000020 l O .data 000000f0 __llvm_prf_vnds +; OBJ-NEXT: 00000110 g O .data 0000000c main +; OBJ-NEXT: 0000011c l .data 00000000 TOC + +; OBJ: RELOCATION RECORDS FOR [.data]: +; OBJ-NEXT: OFFSET TYPE VALUE +; OBJ-NEXT: 00000008 R_REF __llvm_prf_data +; OBJ-NEXT: 00000008 R_REF __llvm_prf_names +; OBJ-NEXT: 00000008 R_REF __llvm_prf_vnds +; OBJ-NEXT: 00000100 R_POS .main +; OBJ-NEXT: 00000104 R_POS TOC