]> granicus.if.org Git - llvm/commitdiff
[AIX]Emit function descriptor csect in assembly
authorXiangling Liao <xiangxdh@gmail.com>
Thu, 26 Sep 2019 19:38:32 +0000 (19:38 +0000)
committerXiangling Liao <xiangxdh@gmail.com>
Thu, 26 Sep 2019 19:38:32 +0000 (19:38 +0000)
This patch emits the function descriptor csect for functions with definitions
under both 32-bit/64-bit mode on AIX.

Differential Revision: https://reviews.llvm.org/D66724

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@373009 91177308-0d34-0410-b5e6-96231b3b80d8

15 files changed:
include/llvm/CodeGen/AsmPrinter.h
include/llvm/MC/MCAsmInfo.h
include/llvm/MC/MCAsmInfoXCOFF.h
include/llvm/MC/MCDirectives.h
include/llvm/MC/MCSymbolXCOFF.h
lib/CodeGen/AsmPrinter/AsmPrinter.cpp
lib/MC/MCAsmInfoXCOFF.cpp
lib/MC/MCAsmStreamer.cpp
lib/MC/MCELFStreamer.cpp
lib/MC/MCMachOStreamer.cpp
lib/MC/MCSectionXCOFF.cpp
lib/MC/XCOFFObjectWriter.cpp
lib/Target/PowerPC/PPCAsmPrinter.cpp
test/CodeGen/PowerPC/aix-xcoff-common.ll
test/CodeGen/PowerPC/test_func_desc.ll [new file with mode: 0644]

index 576854d806a465218717e3f06ddd9f7c0cb5174c..137a1c3b4a56821246ed5318a74f59565c191c5e 100644 (file)
@@ -111,6 +111,10 @@ public:
   /// of each call to runOnMachineFunction().
   MCSymbol *CurrentFnSym = nullptr;
 
+  /// The symbol for the current function descriptor on AIX. This is created
+  /// at the beginning of each call to SetupMachineFunction().
+  MCSymbol *CurrentFnDescSym = nullptr;
+
   /// The symbol used to represent the start of the current function for the
   /// purpose of calculating its size (e.g. using the .size directive). By
   /// default, this is equal to CurrentFnSym.
@@ -304,7 +308,7 @@ public:
 
   /// This should be called when a new MachineFunction is being processed from
   /// runOnMachineFunction.
-  void SetupMachineFunction(MachineFunction &MF);
+  virtual void SetupMachineFunction(MachineFunction &MF);
 
   /// This method emits the body and trailer for a function.
   void EmitFunctionBody();
@@ -414,6 +418,10 @@ public:
 
   virtual void EmitFunctionEntryLabel();
 
+  virtual void EmitFunctionDescriptor() {
+    llvm_unreachable("Function descriptor is target-specific.");
+  }
+
   virtual void EmitMachineConstantPoolValue(MachineConstantPoolValue *MCPV);
 
   /// Targets can override this to change how global constants that are part of
index 95c5662835a23f04baecf2ea573f1d2357c5819d..3261c483e0d807e1dea2ee41e5b2dfc98a3ac740 100644 (file)
@@ -317,6 +317,10 @@ protected:
   /// Defaults to false.
   bool HasLinkOnceDirective = false;
 
+  /// True if we have a .lglobl directive, which is used to emit the information
+  /// of a static symbol into the symbol table. Defaults to false.
+  bool HasDotLGloblDirective = false;
+
   /// This attribute, if not MCSA_Invalid, is used to declare a symbol as having
   /// hidden visibility.  Defaults to MCSA_Hidden.
   MCSymbolAttr HiddenVisibilityAttr = MCSA_Hidden;
@@ -392,6 +396,9 @@ protected:
   // %hi(), and similar unary operators.
   bool HasMipsExpressions = false;
 
+  // If true, emit function descriptor symbol on AIX.
+  bool NeedsFunctionDescriptors = false;
+
 public:
   explicit MCAsmInfo();
   virtual ~MCAsmInfo();
@@ -565,6 +572,8 @@ public:
 
   bool hasLinkOnceDirective() const { return HasLinkOnceDirective; }
 
+  bool hasDotLGloblDirective() const { return HasDotLGloblDirective; }
+
   MCSymbolAttr getHiddenVisibilityAttr() const { return HiddenVisibilityAttr; }
 
   MCSymbolAttr getHiddenDeclarationVisibilityAttr() const {
@@ -647,6 +656,7 @@ public:
   bool canRelaxRelocations() const { return RelaxELFRelocations; }
   void setRelaxELFRelocations(bool V) { RelaxELFRelocations = V; }
   bool hasMipsExpressions() const { return HasMipsExpressions; }
+  bool needsFunctionDescriptors() const { return NeedsFunctionDescriptors; }
 };
 
 } // end namespace llvm
index 2a72ba7398a7a70b5adb7c0e72792a14f98b147f..4a3bacc954e0f128684a3fa72a767aecbdcd68b6 100644 (file)
@@ -18,6 +18,11 @@ class MCAsmInfoXCOFF : public MCAsmInfo {
 
 protected:
   MCAsmInfoXCOFF();
+
+public:
+  // Return true only when the identifier Name does not need quotes to be
+  // syntactically correct for XCOFF.
+  bool isValidUnquotedName(StringRef Name) const override;
 };
 
 } // end namespace llvm
index 4029264c202635910e5637d205fa5258dc2522cf..ea79e68674e5385ebdc40cce68cd7afec02eb015 100644 (file)
@@ -28,6 +28,7 @@ enum MCSymbolAttr {
   MCSA_ELF_TypeNoType,      ///< .type _foo, STT_NOTYPE  # aka @notype
   MCSA_ELF_TypeGnuUniqueObject, /// .type _foo, @gnu_unique_object
   MCSA_Global,              ///< .globl
+  MCSA_LGlobal,             ///< .lglobl (XCOFF)
   MCSA_Hidden,              ///< .hidden (ELF)
   MCSA_IndirectSymbol,      ///< .indirect_symbol (MachO)
   MCSA_Internal,            ///< .internal (ELF)
index 566aa7ca8eb490f68dd904503e7e402fccbbc18c..98ecd24669262f2be8caee23477777adb2926922 100644 (file)
@@ -35,14 +35,14 @@ public:
     return StorageClass.getValue();
   }
 
-  void setContainingCsect(const MCSectionXCOFF *C) {
+  void setContainingCsect(MCSectionXCOFF *C) {
     assert((!ContainingCsect || ContainingCsect == C) &&
            "Trying to set a containing csect that doesn't match the one that"
            "this symbol is already mapped to.");
     ContainingCsect = C;
   }
 
-  const MCSectionXCOFF *getContainingCsect() const {
+  MCSectionXCOFF *getContainingCsect() const {
     assert(ContainingCsect &&
            "Trying to get containing csect but none was set.");
     return ContainingCsect;
@@ -50,7 +50,7 @@ public:
 
 private:
   Optional<XCOFF::StorageClass> StorageClass;
-  const MCSectionXCOFF *ContainingCsect = nullptr;
+  MCSectionXCOFF *ContainingCsect = nullptr;
 };
 
 } // end namespace llvm
index 3a53a02cce5618a59abf589d462a7dd5b9454daa..5664a47aeea277f19fb275345f8758f3106a44c3 100644 (file)
 #include "llvm/MC/MCSectionCOFF.h"
 #include "llvm/MC/MCSectionELF.h"
 #include "llvm/MC/MCSectionMachO.h"
+#include "llvm/MC/MCSectionXCOFF.h"
 #include "llvm/MC/MCStreamer.h"
 #include "llvm/MC/MCSubtargetInfo.h"
 #include "llvm/MC/MCSymbol.h"
 #include "llvm/MC/MCSymbolELF.h"
+#include "llvm/MC/MCSymbolXCOFF.h"
 #include "llvm/MC/MCTargetOptions.h"
 #include "llvm/MC/MCValue.h"
 #include "llvm/MC/SectionKind.h"
@@ -426,7 +428,10 @@ void AsmPrinter::EmitLinkage(const GlobalValue *GV, MCSymbol *GVSym) const {
     OutStreamer->EmitSymbolAttribute(GVSym, MCSA_Global);
     return;
   case GlobalValue::PrivateLinkage:
+    return;
   case GlobalValue::InternalLinkage:
+    if (MAI->hasDotLGloblDirective())
+      OutStreamer->EmitSymbolAttribute(GVSym, MCSA_LGlobal);
     return;
   case GlobalValue::AppendingLinkage:
   case GlobalValue::AvailableExternallyLinkage:
@@ -662,6 +667,10 @@ void AsmPrinter::EmitFunctionHeader() {
   OutStreamer->SwitchSection(getObjFileLowering().SectionForGlobal(&F, TM));
   EmitVisibility(CurrentFnSym, F.getVisibility());
 
+  if (MAI->needsFunctionDescriptors() &&
+      F.getLinkage() != GlobalValue::InternalLinkage)
+    EmitLinkage(&F, CurrentFnDescSym);
+
   EmitLinkage(&F, CurrentFnSym);
   if (MAI->hasFunctionAlignment())
     EmitAlignment(MF->getAlignment(), &F);
@@ -697,8 +706,13 @@ void AsmPrinter::EmitFunctionHeader() {
     }
   }
 
-  // Emit the CurrentFnSym.  This is a virtual function to allow targets to
-  // do their wild and crazy things as required.
+  // Emit the function descriptor. This is a virtual function to allow targets
+  // to emit their specific function descriptor.
+  if (MAI->needsFunctionDescriptors())
+    EmitFunctionDescriptor();
+
+  // Emit the CurrentFnSym. This is a virtual function to allow targets to do
+  // their wild and crazy things as required.
   EmitFunctionEntryLabel();
 
   // If the function had address-taken blocks that got deleted, then we have
@@ -1644,8 +1658,27 @@ MCSymbol *AsmPrinter::getCurExceptionSym() {
 
 void AsmPrinter::SetupMachineFunction(MachineFunction &MF) {
   this->MF = &MF;
+
   // Get the function symbol.
-  CurrentFnSym = getSymbol(&MF.getFunction());
+  if (MAI->needsFunctionDescriptors()) {
+    assert(TM.getTargetTriple().isOSAIX() && "Function descriptor is only"
+                                             " supported on AIX.");
+    assert(CurrentFnDescSym && "The function descriptor symbol needs to be"
+                                          " initalized first.");
+
+    // Get the function entry point symbol.
+    CurrentFnSym =
+        OutContext.getOrCreateSymbol("." + CurrentFnDescSym->getName());
+
+    const Function &F = MF.getFunction();
+    MCSectionXCOFF *FnEntryPointSec =
+        cast<MCSectionXCOFF>(getObjFileLowering().SectionForGlobal(&F, TM));
+    // Set the containing csect.
+    cast<MCSymbolXCOFF>(CurrentFnSym)->setContainingCsect(FnEntryPointSec);
+  } else {
+    CurrentFnSym = getSymbol(&MF.getFunction());
+  }
+
   CurrentFnSymForSize = CurrentFnSym;
   CurrentFnBegin = nullptr;
   CurExceptionSym = nullptr;
index 13939f6a65f85caa491e4700acd04d3608563e44..65fe8848e20fbeab715ddfaffc91abb6f474db3a 100644 (file)
@@ -20,5 +20,16 @@ MCAsmInfoXCOFF::MCAsmInfoXCOFF() {
   UseDotAlignForAlignment = true;
   AsciiDirective = nullptr; // not supported
   AscizDirective = nullptr; // not supported
+  NeedsFunctionDescriptors = true;
+  HasDotLGloblDirective = true;
   Data64bitsDirective = "\t.llong\t";
+  SupportsQuotedNames = false;
+}
+
+bool MCAsmInfoXCOFF::isValidUnquotedName(StringRef Name) const {
+  // FIXME: Remove this function when we stop using "TOC[TC0]" as a symbol name.
+  if (Name.equals("TOC[TC0]"))
+    return true;
+
+  return MCAsmInfo::isValidUnquotedName(Name);
 }
index 55bcc914ea32d0a0f63327921e29b425ac6243f8..dd27d0bc8a5265f43d2bfd558435c20170fe61cd 100644 (file)
@@ -650,6 +650,7 @@ bool MCAsmStreamer::EmitSymbolAttribute(MCSymbol *Symbol,
   case MCSA_Global: // .globl/.global
     OS << MAI->getGlobalDirective();
     break;
+  case MCSA_LGlobal:        OS << "\t.lglobl\t";          break;
   case MCSA_Hidden:         OS << "\t.hidden\t";          break;
   case MCSA_IndirectSymbol: OS << "\t.indirect_symbol\t"; break;
   case MCSA_Internal:       OS << "\t.internal\t";        break;
index 816e742b2631acecb3908858ed5612d0411bea79..e411e24921c4f6b74c53b88bab110fe1b257d783 100644 (file)
@@ -277,6 +277,9 @@ bool MCELFStreamer::EmitSymbolAttribute(MCSymbol *S, MCSymbolAttr Attribute) {
 
   case MCSA_AltEntry:
     llvm_unreachable("ELF doesn't support the .alt_entry attribute");
+
+  case MCSA_LGlobal:
+    llvm_unreachable("ELF doesn't support the .lglobl attribute");
   }
 
   return true;
index 613f255a4ea47cfb9d19ce96288f07a6989010a2..8e558a36b7a1fc5481248e11b700baceed35dd3c 100644 (file)
@@ -330,6 +330,7 @@ bool MCMachOStreamer::EmitSymbolAttribute(MCSymbol *Sym,
   case MCSA_Protected:
   case MCSA_Weak:
   case MCSA_Local:
+  case MCSA_LGlobal:
     return false;
 
   case MCSA_Global:
index db277521db2561f58f67a54001e186e333af34b2..d52959f15f928fdf81c0fef4f2f9ea25b19e7486 100644 (file)
@@ -15,26 +15,46 @@ using namespace llvm;
 
 MCSectionXCOFF::~MCSectionXCOFF() = default;
 
+static StringRef getMappingClassString(XCOFF::StorageMappingClass SMC) {
+  switch (SMC) {
+  case XCOFF::XMC_DS:
+    return "DS";
+  case XCOFF::XMC_RW:
+    return "RW";
+  case XCOFF::XMC_PR:
+    return "PR";
+  default:
+    report_fatal_error("Unhandled storage-mapping class.");
+  }
+}
+
 void MCSectionXCOFF::PrintSwitchToSection(const MCAsmInfo &MAI, const Triple &T,
                                           raw_ostream &OS,
                                           const MCExpr *Subsection) const {
   if (getKind().isText()) {
     if (getMappingClass() != XCOFF::XMC_PR)
-      llvm_unreachable("Unsupported storage-mapping class for .text csect");
+      report_fatal_error("Unhandled storage-mapping class for .text csect");
 
     OS << "\t.csect " << getSectionName() << "["
-       << "PR"
+       << getMappingClassString(getMappingClass())
        << "]" << '\n';
     return;
   }
 
   if (getKind().isData()) {
-    assert(getMappingClass() == XCOFF::XMC_RW &&
-           "Unhandled storage-mapping class for data section.");
-
-    OS << "\t.csect " << getSectionName() << "["
-       << "RW"
-       << "]" << '\n';
+    switch (getMappingClass()) {
+    case XCOFF::XMC_RW:
+    case XCOFF::XMC_DS:
+      OS << "\t.csect " << getSectionName() << "["
+         << getMappingClassString(getMappingClass()) << "]" << '\n';
+      break;
+    case XCOFF::XMC_TC0:
+      OS << "\t.toc\n";
+      break;
+    default:
+      report_fatal_error(
+          "Unhandled storage-mapping class for .data csect.");
+    }
     return;
   }
 
index e831d3e763f74117dd18de133c059b5f2b999218..5d8735b017d3f8eb48284974dcbe0480c2a527b6 100644 (file)
@@ -235,6 +235,9 @@ void XCOFFObjectWriter::executePostLayoutBinding(
         break;
       }
       report_fatal_error("Unhandled mapping of read-write csect to section.");
+    case XCOFF::XMC_TC0:
+      // TODO FIXME Handle emiting the TOC base.
+      break;
     case XCOFF::XMC_BS:
       assert(XCOFF::XTY_CM == MCSec->getCSectType() &&
              "Mapping invalid csect. CSECT with bss storage class must be "
index 6e0fdd8574ea47cd739e0b0952cc026d37092950..124c1827154ecdc5f5c718b863e316a53c7b917c 100644 (file)
@@ -167,7 +167,13 @@ public:
 
   StringRef getPassName() const override { return "AIX PPC Assembly Printer"; }
 
+  void SetupMachineFunction(MachineFunction &MF) override;
+
   void EmitGlobalVariable(const GlobalVariable *GV) override;
+
+  void EmitFunctionDescriptor() override;
+
+  void EmitEndOfAsmFile(Module &) override;
 };
 
 } // end anonymous namespace
@@ -1669,6 +1675,18 @@ bool PPCDarwinAsmPrinter::doFinalization(Module &M) {
   return AsmPrinter::doFinalization(M);
 }
 
+void PPCAIXAsmPrinter::SetupMachineFunction(MachineFunction &MF) {
+  // Get the function descriptor symbol.
+  CurrentFnDescSym = getSymbol(&MF.getFunction());
+  // Set the containing csect.
+  MCSectionXCOFF *FnDescSec = OutStreamer->getContext().getXCOFFSection(
+      CurrentFnDescSym->getName(), XCOFF::XMC_DS, XCOFF::XTY_SD,
+      XCOFF::C_HIDEXT, SectionKind::getData());
+  cast<MCSymbolXCOFF>(CurrentFnDescSym)->setContainingCsect(FnDescSec);
+
+  return AsmPrinter::SetupMachineFunction(MF);
+}
+
 void PPCAIXAsmPrinter::EmitGlobalVariable(const GlobalVariable *GV) {
   // Early error checking limiting what is supported.
   if (GV->isThreadLocal())
@@ -1718,6 +1736,45 @@ void PPCAIXAsmPrinter::EmitGlobalVariable(const GlobalVariable *GV) {
   EmitGlobalConstant(GV->getParent()->getDataLayout(), GV->getInitializer());
 }
 
+void PPCAIXAsmPrinter::EmitFunctionDescriptor() {
+  const DataLayout &DL = getDataLayout();
+  const unsigned PointerSize = DL.getPointerSizeInBits() == 64 ? 8 : 4;
+
+  MCSectionSubPair Current = OutStreamer->getCurrentSection();
+  // Emit function descriptor.
+  OutStreamer->SwitchSection(
+      cast<MCSymbolXCOFF>(CurrentFnDescSym)->getContainingCsect());
+  OutStreamer->EmitLabel(CurrentFnDescSym);
+  // Emit function entry point address.
+  OutStreamer->EmitValue(MCSymbolRefExpr::create(CurrentFnSym, OutContext),
+                         PointerSize);
+  // Emit TOC base address.
+  MCSymbol *TOCBaseSym = OutContext.getOrCreateSymbol(StringRef("TOC[TC0]"));
+  OutStreamer->EmitValue(MCSymbolRefExpr::create(TOCBaseSym, OutContext),
+                         PointerSize);
+  // Emit a null environment pointer.
+  OutStreamer->EmitIntValue(0, PointerSize);
+
+  OutStreamer->SwitchSection(Current.first, Current.second);
+}
+
+void PPCAIXAsmPrinter::EmitEndOfAsmFile(Module &M) {
+  // If there are no functions in this module, we will never need to reference
+  // the TOC base.
+  if (M.empty())
+    return;
+
+  // Emit TOC base.
+  MCSymbol *TOCBaseSym = OutContext.getOrCreateSymbol(StringRef("TOC[TC0]"));
+  MCSectionXCOFF *TOCBaseSection = OutStreamer->getContext().getXCOFFSection(
+      StringRef("TOC"), XCOFF::XMC_TC0, XCOFF::XTY_SD, XCOFF::C_HIDEXT,
+      SectionKind::getData());
+  cast<MCSymbolXCOFF>(TOCBaseSym)->setContainingCsect(TOCBaseSection);
+  // Switch to section to emit TOC base.
+  OutStreamer->SwitchSection(TOCBaseSection);
+}
+
+
 /// createPPCAsmPrinterPass - Returns a pass that prints the PPC assembly code
 /// for a MachineFunction to the given output stream, in a format that the
 /// Darwin assembler can deal with.
index a3e135f15b411cf9badc2ad7b77b8e54c346fa36..ffae4a42d15794317f3b3fcf343150852c41e0ae 100644 (file)
@@ -21,6 +21,8 @@
 
 @array = common local_unnamed_addr global [33 x i8] zeroinitializer, align 1
 
+; CHECK-NOT: .toc
+
 ; CHECK:      .csect .text[PR]
 ; CHECK-NEXT:  .file
 ; CHECK-NEXT: .comm   a,4,2
diff --git a/test/CodeGen/PowerPC/test_func_desc.ll b/test/CodeGen/PowerPC/test_func_desc.ll
new file mode 100644 (file)
index 0000000..3cd16b9
--- /dev/null
@@ -0,0 +1,74 @@
+; RUN: llc -mtriple powerpc-ibm-aix-xcoff < %s | \
+; RUN: FileCheck --check-prefixes=CHECK,32BIT %s
+
+; RUN: llc -mtriple powerpc64-ibm-aix-xcoff < %s | \
+; RUN: FileCheck --check-prefixes=CHECK,64BIT %s
+
+
+define i32 @foo() {
+entry:
+  ret i32 3
+}
+
+define i32 @main() {
+entry:
+  %0 = call i32 @foo()
+  %1 = call i32 bitcast (i32 (...)* @extern_foo to i32 ()*)()
+  %2 = call i32 @static_foo()
+  %3 = add nsw i32 %0, %1
+  %4 = add nsw i32 %3, %2
+  ret i32 %4
+}
+
+declare i32 @extern_foo(...)
+
+define internal i32 @static_foo() {
+entry:
+  ret i32 3
+}
+
+; CHECK: .globl foo
+; CHECK: .globl .foo
+; CHECK: .csect foo[DS]
+; CHECK-NEXT: foo:
+; 32BIT: .long .foo
+; 32BIT-NEXT: .long TOC[TC0]
+; 32BIT-NEXT: .long 0
+; 64BIT: .llong .foo
+; 64BIT-NEXT: .llong TOC[TC0]
+; 64BIT-NEXT: .llong 0
+; CHECK-NEXT: .csect .text[PR]
+; CHECK-LABEL: .foo:
+
+; CHECK: .globl main
+; CHECK: .globl .main
+; CHECK: .csect main[DS]
+; CHECK-NEXT: main:
+; 32BIT: .long .main
+; 32BIT-NEXT: .long TOC[TC0]
+; 32BIT-NEXT: .long 0
+; 64BIT: .llong .main
+; 64BIT-NEXT: .llong TOC[TC0]
+; 64BIT-NEXT: .llong 0
+; CHECK-NEXT: .csect .text[PR]
+; CHECK-LABEL: .main:
+; CHECK: bl .foo
+; CHECK: bl .extern_foo
+; CHECK: bl .static_foo
+
+; CHECK: .lglobl .static_foo
+; CHECK: .csect static_foo[DS]
+; CHECK-NEXT: static_foo:
+; 32BIT: .long .static_foo
+; 32BIT-NEXT: .long TOC[TC0]
+; 32BIT-NEXT: .long 0
+; 64BIT: .llong .static_foo
+; 64BIT-NEXT: .llong TOC[TC0]
+; 64BIT-NEXT: .llong 0
+; CHECK-NEXT: .csect .text[PR]
+; CHECK-LABEL: .static_foo:
+
+; CHECK-NOT: .csect extern_foo
+
+; CHECK: .toc
+; CHECK-NOT: .tc