From 49dcd08c3d963e79d0710faf0e4024eb9b84bc8b Mon Sep 17 00:00:00 2001 From: esmeyi Date: Thu, 23 Mar 2023 05:09:47 -0400 Subject: [PATCH] [XCOFF] support the ref directive for object generation. Summary: A R_REF relocation as a non-relocating reference is required to prevent garbage collection (by the binder) of the ref symbol in object generation. Reviewed By: shchenz Differential Revision: https://reviews.llvm.org/D144356 --- llvm/include/llvm/MC/MCStreamer.h | 2 +- llvm/include/llvm/MC/MCXCOFFStreamer.h | 5 +-- llvm/lib/MC/MCAsmStreamer.cpp | 7 ++-- llvm/lib/MC/MCStreamer.cpp | 2 +- llvm/lib/MC/MCXCOFFStreamer.cpp | 15 +++++++ llvm/lib/MC/XCOFFObjectWriter.cpp | 5 ++- .../Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp | 9 +++++ .../Target/PowerPC/MCTargetDesc/PPCFixupKinds.h | 3 +- .../PowerPC/MCTargetDesc/PPCXCOFFObjectWriter.cpp | 6 +++ llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp | 18 ++++++--- llvm/test/CodeGen/PowerPC/pgo-ref-directive.ll | 46 ++++++++++++++++++++-- 11 files changed, 98 insertions(+), 20 deletions(-) diff --git a/llvm/include/llvm/MC/MCStreamer.h b/llvm/include/llvm/MC/MCStreamer.h index aa39954..f5891b2 100644 --- a/llvm/include/llvm/MC/MCStreamer.h +++ b/llvm/include/llvm/MC/MCStreamer.h @@ -645,7 +645,7 @@ public: /// 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); /// Emit an ELF .size directive. /// diff --git a/llvm/include/llvm/MC/MCXCOFFStreamer.h b/llvm/include/llvm/MC/MCXCOFFStreamer.h index a437fae..aea2a32 100644 --- a/llvm/include/llvm/MC/MCXCOFFStreamer.h +++ b/llvm/include/llvm/MC/MCXCOFFStreamer.h @@ -31,10 +31,7 @@ public: 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 index 006f697..fa1ab27 100644 --- a/llvm/lib/MC/MCAsmStreamer.cpp +++ b/llvm/lib/MC/MCAsmStreamer.cpp @@ -194,7 +194,7 @@ public: void emitXCOFFRenameDirective(const MCSymbol *Name, StringRef Rename) override; - void emitXCOFFRefDirective(StringRef Name) override; + void emitXCOFFRefDirective(const MCSymbol *Symbol) override; void emitXCOFFExceptDirective(const MCSymbol *Symbol, const MCSymbol *Trap, @@ -943,8 +943,9 @@ void MCAsmStreamer::emitXCOFFRenameDirective(const MCSymbol *Name, 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 index 517e258..4dd3163 100644 --- a/llvm/lib/MC/MCStreamer.cpp +++ b/llvm/lib/MC/MCStreamer.cpp @@ -1190,7 +1190,7 @@ void MCStreamer::emitXCOFFRenameDirective(const MCSymbol *Name, "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 index 25a678c..d8ac07b 100644 --- a/llvm/lib/MC/MCXCOFFStreamer.cpp +++ b/llvm/lib/MC/MCXCOFFStreamer.cpp @@ -81,6 +81,21 @@ void MCXCOFFStreamer::emitXCOFFSymbolLinkageWithVisibility( emitSymbolAttribute(Symbol, Visibility); } +void MCXCOFFStreamer::emitXCOFFRefDirective(const MCSymbol *Symbol) { + // Add a Fixup here to later record a relocation of type R_REF to prevent the + // ref symbol from being garbage collected (by the binder). + MCDataFragment *DF = getOrCreateDataFragment(); + const MCSymbolRefExpr *SRE = MCSymbolRefExpr::create(Symbol, getContext()); + std::optional MaybeKind = + getAssembler().getBackend().getFixupKind("R_REF"); + if (!MaybeKind) + report_fatal_error("failed to get fixup kind for R_REF relocation"); + + MCFixupKind Kind = *MaybeKind; + MCFixup Fixup = MCFixup::create(DF->getContents().size(), SRE, Kind); + DF->getFixups().push_back(Fixup); +} + 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 index c79bdeb..6452050 100644 --- a/llvm/lib/MC/XCOFFObjectWriter.cpp +++ b/llvm/lib/MC/XCOFFObjectWriter.cpp @@ -663,7 +663,10 @@ void XCOFFObjectWriter::recordRelocation(MCAssembler &Asm, // instr address plus any constant value. FixedValue = SectionMap[SymASec]->Address - BRInstrAddress + Target.getConstant(); - } + } else if (Type == XCOFF::RelocationType::R_REF) + // The FixedValue should always be 0 since it specifies a nonrelocating + // reference. + FixedValue = 0; assert((Fixup.getOffset() <= MaxRawDataSize - Layout.getFragmentOffset(Fragment)) && diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp index 227bd59..a814bb1 100644 --- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp +++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp @@ -238,6 +238,8 @@ public: createObjectTargetWriter() const override { return createPPCXCOFFObjectWriter(TT.isArch64Bit()); } + + std::optional getFixupKind(StringRef Name) const override; }; } // end anonymous namespace @@ -272,6 +274,13 @@ ELFPPCAsmBackend::getFixupKind(StringRef Name) const { return std::nullopt; } +std::optional +XCOFFPPCAsmBackend::getFixupKind(StringRef Name) const { + return StringSwitch>(Name) + .Case("R_REF", (MCFixupKind)PPC::fixup_ppc_nofixup) + .Default(std::nullopt); +} + MCAsmBackend *llvm::createPPCAsmBackend(const Target &T, const MCSubtargetInfo &STI, const MCRegisterInfo &MRI, diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCFixupKinds.h b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCFixupKinds.h index df0c666..9e8ee9f 100644 --- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCFixupKinds.h +++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCFixupKinds.h @@ -48,7 +48,8 @@ enum Fixups { /// Not a true fixup, but ties a symbol to a call to __tls_get_addr for the /// TLS general and local dynamic models, or inserts the thread-pointer - /// register number. + /// register number. It can also be used to tie the ref symbol to prevent it + /// from being garbage collected on AIX. fixup_ppc_nofixup, /// A 16-bit fixup corresponding to lo16(_foo) with implied 3 zero bits for diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCXCOFFObjectWriter.cpp b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCXCOFFObjectWriter.cpp index 729cb35..b6e749b 100644 --- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCXCOFFObjectWriter.cpp +++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCXCOFFObjectWriter.cpp @@ -90,6 +90,12 @@ std::pair PPCXCOFFObjectWriter::getRelocTypeAndSignSize( return {XCOFF::RelocationType::R_RBR, EncodedSignednessIndicator | 25}; case PPC::fixup_ppc_br24abs: return {XCOFF::RelocationType::R_RBA, EncodedSignednessIndicator | 25}; + case PPC::fixup_ppc_nofixup: { + if (Modifier == MCSymbolRefExpr::VK_None) + return {XCOFF::RelocationType::R_REF, 0}; + else + llvm_unreachable("Unsupported Modifier"); + } break; case FK_Data_4: case FK_Data_8: const uint8_t SignAndSizeForFKData = diff --git a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp index 1ecaeab..7c6fd3b 100644 --- a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp +++ b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp @@ -2517,16 +2517,22 @@ void PPCAIXAsmPrinter::emitPGORefs() { 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 index 172affa..201af2f 100644 --- a/llvm/test/CodeGen/PowerPC/pgo-ref-directive.ll +++ b/llvm/test/CodeGen/PowerPC/pgo-ref-directive.ll @@ -1,9 +1,22 @@ ; RUN: rm -rf %t && split-file %s %t -; RUN: llc -verify-machineinstrs -mcpu=pwr4 -mattr=-altivec -mtriple powerpc-ibm-aix-xcoff -xcoff-traceback-table=false < %t/no-ref.ll | FileCheck %s --check-prefixes=NOREF -; 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 < %t/no-ref.ll | FileCheck %s --check-prefixes=NOREF +; RUN: llc -verify-machineinstrs -mcpu=pwr4 -mattr=-altivec -mtriple powerpc-ibm-aix-xcoff \ +; RUN: -xcoff-traceback-table=false --filetype=obj < %t/no-ref.ll -o %t/no-ref.o +; RUN: llvm-objdump %t/no-ref.o -r | FileCheck %s --check-prefix=NOREF-OBJ +; RUN: llc -verify-machineinstrs -mcpu=pwr4 -mattr=-altivec -mtriple powerpc-ibm-aix-xcoff \ +; RUN: -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 \ +; RUN: -xcoff-traceback-table=false --filetype=obj < %t/no-vnds.ll -o %t/no-vnds.o +; RUN: llvm-objdump %t/no-vnds.o -r | FileCheck %s --check-prefix=NOVNDS-OBJ + +; RUN: llc -verify-machineinstrs -mcpu=pwr4 -mattr=-altivec -mtriple powerpc-ibm-aix-xcoff \ +; RUN: -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=WITHVNDS-OBJ ;--- no-ref.ll ; The absence of a __llvm_prf_cnts section should stop generating the .refs. @@ -27,6 +40,10 @@ entry: ; NOREF-NOT: .ref __llvm_prf_names ; NOREF-NOT: .ref __llvm_prf_vnds +; NOREF-OBJ-NOT: R_REF __llvm_prf_data +; NOREF-OBJ-NOT: R_REF __llvm_prf_names +; NOREF-OBJ-NOT: R_REF __llvm_prf_vnds + ;--- no-vnds.ll ; This is the most common case. When -fprofile-generate is used and there exists executable code, we generate the __llvm_prf_cnts, __llvm_prf_data, and __llvm_prf_names sections. ; @@ -56,6 +73,10 @@ entry: ; NOVNDS-NEXT: .ref __llvm_prf_names[RO] ; NOVNDS-NOT: .ref __llvm_prf_vnds +; NOVNDS-OBJ: 00000008 R_REF __llvm_prf_data +; NOVNDS-OBJ: 00000008 R_REF __llvm_prf_names +; NOVNDS-OBJ-NOT: R_REF __llvm_prf_vnds + ;--- with-vnds.ll ; When value profiling is needed, the PGO instrumentation generates variables in the __llvm_prf_vnds section, so we generate a .ref for them too. ; @@ -80,3 +101,22 @@ entry: ; WITHVNDS-NEXT: .ref __llvm_prf_data[RW] ; WITHVNDS-NEXT: .ref __llvm_prf_names[RO] ; WITHVNDS-NEXT: .ref __llvm_prf_vnds[RW] + +; WITHVNDS-OBJ: SYMBOL TABLE: +; WITHVNDS-OBJ-NEXT: 00000000 df *DEBUG* 00000000 +; WITHVNDS-OBJ-NEXT: 00000000 l .text 00000008 .text +; WITHVNDS-OBJ-NEXT: 00000000 g F .text (csect: .text) 00000000 .main +; WITHVNDS-OBJ-NEXT: 00000008 l .text 00000006 __llvm_prf_names +; WITHVNDS-OBJ-NEXT: 00000010 l O .data 00000008 __llvm_prf_cnts +; WITHVNDS-OBJ-NEXT: 00000018 l O .data 00000008 __llvm_prf_data +; WITHVNDS-OBJ-NEXT: 00000020 l O .data 000000f0 __llvm_prf_vnds +; WITHVNDS-OBJ-NEXT: 00000110 g O .data 0000000c main +; WITHVNDS-OBJ-NEXT: 0000011c l .data 00000000 TOC + +; WITHVNDS-OBJ: RELOCATION RECORDS FOR [.data]: +; WITHVNDS-OBJ-NEXT: OFFSET TYPE VALUE +; WITHVNDS-OBJ-NEXT: 00000008 R_REF __llvm_prf_data +; WITHVNDS-OBJ-NEXT: 00000008 R_REF __llvm_prf_names +; WITHVNDS-OBJ-NEXT: 00000008 R_REF __llvm_prf_vnds +; WITHVNDS-OBJ-NEXT: 00000100 R_POS .main +; WITHVNDS-OBJ-NEXT: 00000104 R_POS TOC -- 2.7.4