[XCOFF] support the ref directive for object generation.
authoresmeyi <esme.yi@ibm.com>
Thu, 23 Mar 2023 09:09:47 +0000 (05:09 -0400)
committeresmeyi <esme.yi@ibm.com>
Thu, 23 Mar 2023 09:09:47 +0000 (05:09 -0400)
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
llvm/include/llvm/MC/MCXCOFFStreamer.h
llvm/lib/MC/MCAsmStreamer.cpp
llvm/lib/MC/MCStreamer.cpp
llvm/lib/MC/MCXCOFFStreamer.cpp
llvm/lib/MC/XCOFFObjectWriter.cpp
llvm/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp
llvm/lib/Target/PowerPC/MCTargetDesc/PPCFixupKinds.h
llvm/lib/Target/PowerPC/MCTargetDesc/PPCXCOFFObjectWriter.cpp
llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
llvm/test/CodeGen/PowerPC/pgo-ref-directive.ll

index aa39954..f5891b2 100644 (file)
@@ -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.
   ///
index a437fae..aea2a32 100644 (file)
@@ -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 "
index 006f697..fa1ab27 100644 (file)
@@ -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();
 }
 
index 517e258..4dd3163 100644 (file)
@@ -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");
 }
 
index 25a678c..d8ac07b 100644 (file)
@@ -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<MCFixupKind> 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,
index c79bdeb..6452050 100644 (file)
@@ -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)) &&
index 227bd59..a814bb1 100644 (file)
@@ -238,6 +238,8 @@ public:
   createObjectTargetWriter() const override {
     return createPPCXCOFFObjectWriter(TT.isArch64Bit());
   }
+
+  std::optional<MCFixupKind> getFixupKind(StringRef Name) const override;
 };
 
 } // end anonymous namespace
@@ -272,6 +274,13 @@ ELFPPCAsmBackend::getFixupKind(StringRef Name) const {
   return std::nullopt;
 }
 
+std::optional<MCFixupKind>
+XCOFFPPCAsmBackend::getFixupKind(StringRef Name) const {
+  return StringSwitch<std::optional<MCFixupKind>>(Name)
+      .Case("R_REF", (MCFixupKind)PPC::fixup_ppc_nofixup)
+      .Default(std::nullopt);
+}
+
 MCAsmBackend *llvm::createPPCAsmBackend(const Target &T,
                                         const MCSubtargetInfo &STI,
                                         const MCRegisterInfo &MRI,
index df0c666..9e8ee9f 100644 (file)
@@ -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
index 729cb35..b6e749b 100644 (file)
@@ -90,6 +90,12 @@ std::pair<uint8_t, uint8_t> 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 =
index 1ecaeab..7c6fd3b 100644 (file)
@@ -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);
+    }
   }
 }
 
index 172affa..201af2f 100644 (file)
@@ -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 <stdin>
+; 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