[clang] [llvm] [AIX][TOC] Add -mtocdata/-mno-tocdata options on AIX (PR #67999)

Zaara Syeda via cfe-commits cfe-commits at lists.llvm.org
Tue Feb 20 08:35:39 PST 2024


https://github.com/syzaara updated https://github.com/llvm/llvm-project/pull/67999

>From 841345a110db787920ca8acbc08801436f2b36db Mon Sep 17 00:00:00 2001
From: Zaara Syeda <syzaara at cpap8104.rtp.raleigh.ibm.com>
Date: Thu, 28 Sep 2023 15:01:56 -0400
Subject: [PATCH 1/9] [AIX][TOC] Add -mtocdata/-mno-tocdata options on AIX

This patch enables support that the XL compiler had for AIX under
-qdatalocal/-qdataimported.
---
 clang/docs/UsersManual.rst                    | 56 ++++++++++++
 clang/include/clang/Basic/CodeGenOptions.h    |  9 ++
 .../clang/Basic/DiagnosticDriverKinds.td      |  3 +
 .../clang/Basic/DiagnosticFrontendKinds.td    |  2 +
 clang/include/clang/Driver/Options.td         | 23 +++++
 clang/lib/CodeGen/CGDecl.cpp                  |  1 +
 clang/lib/CodeGen/CodeGenModule.cpp           | 28 ++++++
 clang/lib/CodeGen/Targets/PPC.cpp             | 61 +++++++++++++
 clang/lib/Driver/ToolChains/AIX.cpp           | 89 +++++++++++++++++++
 clang/lib/Frontend/CompilerInstance.cpp       |  5 ++
 .../test/CodeGen/PowerPC/toc-data-attribute.c | 61 +++++++++++++
 .../CodeGen/PowerPC/toc-data-attribute.cpp    | 43 +++++++++
 .../CodeGen/PowerPC/toc-data-diagnostics.c    | 69 ++++++++++++++
 .../PowerPC/toc-data-structs-arrays.cpp       | 64 +++++++++++++
 clang/test/CodeGen/toc-data.c                 | 31 +++++++
 clang/test/Driver/toc-conf.c                  | 30 +++++++
 clang/test/Driver/tocdata-cc1.c               | 16 ++++
 llvm/include/llvm/ADT/STLExtras.h             | 13 +++
 llvm/lib/MC/MCSectionXCOFF.cpp                |  3 +-
 llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp   | 20 ++---
 .../CodeGen/PowerPC/toc-data-large-array.ll   | 16 ++++
 .../CodeGen/PowerPC/toc-data-struct-array.ll  | 29 ++++++
 22 files changed, 655 insertions(+), 17 deletions(-)
 create mode 100644 clang/test/CodeGen/PowerPC/toc-data-attribute.c
 create mode 100644 clang/test/CodeGen/PowerPC/toc-data-attribute.cpp
 create mode 100644 clang/test/CodeGen/PowerPC/toc-data-diagnostics.c
 create mode 100644 clang/test/CodeGen/PowerPC/toc-data-structs-arrays.cpp
 create mode 100644 clang/test/CodeGen/toc-data.c
 create mode 100644 clang/test/Driver/toc-conf.c
 create mode 100644 clang/test/Driver/tocdata-cc1.c
 create mode 100644 llvm/test/CodeGen/PowerPC/toc-data-large-array.ll
 create mode 100644 llvm/test/CodeGen/PowerPC/toc-data-struct-array.ll

diff --git a/clang/docs/UsersManual.rst b/clang/docs/UsersManual.rst
index 7391e4cf3a9aeb..2ce6da677e91e8 100644
--- a/clang/docs/UsersManual.rst
+++ b/clang/docs/UsersManual.rst
@@ -4227,7 +4227,63 @@ Clang expects the GCC executable "gcc.exe" compiled for
 
 AIX
 ^^^
+TOC Data Transformation
+"""""""""""""""""""""""
+TOC data transformation is off by default (``-mno-tocdata``).
+When ``-mtocdata`` is specified, the TOC data transformation will be applied to
+all suitable variables with static storage duration, including static data
+members of classes and block-scope static variables (if not marked as exceptions,
+see further below).
 
+Suitable variables must:
+
+-  have complete types
+-  be independently generated (i.e., not placed in a pool)
+-  be at most as large as a pointer
+-  not be aligned more strictly than a pointer
+-  not be structs containing flexible array members
+-  not have internal linkage
+-  not have aliases
+-  not have section attributes
+
+The TOC data transformation results in the variable, not its address,
+being placed in the TOC. This eliminates the need to load the address of the
+variable from the TOC.
+
+Note:
+If the TOC data transformation is applied to a variable whose definition
+is imported, the linker will generate fixup code for reading or writing to the
+variable.
+
+Any internal linkage variables specified to any TOC data options will be ignored.
+
+**Options:**
+
+.. option:: -mno-tocdata
+
+  This is the default behaviour. Only variables explicitly specified with
+  ``-mtocdata=`` will have the TOC data transformation applied.
+
+.. option:: -mtocdata
+
+  Apply the TOC data transformation to all suitable variables with static
+  storage duration (including static data members of classes and block-scope
+  static variables) that are not explicitly specified with ``-mno-tocdata=``.
+
+.. option:: -mno-tocdata=
+
+  Can be used in conjunction with ``-mtocdata`` to mark the comma-separated
+  list of external linkage variables, specified using their mangled names, as
+  exceptions to ``-mtocdata``.
+
+.. option:: -mtocdata=
+
+  Apply the TOC data transformation to the comma-separated list of external
+  linkage variables, specified using their mangled names, if they are suitable.
+  Emit diagnostics for all unsuitable variables specified.
+
+Default Visibility Export Mapping
+"""""""""""""""""""""""""""""""""
 The ``-mdefault-visibility-export-mapping=`` option can be used to control
 mapping of default visibility to an explicit shared object export
 (i.e. XCOFF exported visibility). Three values are provided for the option:
diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h
index 3f8fe385fef3df..ecf3914228d92b 100644
--- a/clang/include/clang/Basic/CodeGenOptions.h
+++ b/clang/include/clang/Basic/CodeGenOptions.h
@@ -403,6 +403,15 @@ class CodeGenOptions : public CodeGenOptionsBase {
 
   /// List of pass builder callbacks.
   std::vector<std::function<void(llvm::PassBuilder &)>> PassBuilderCallbacks;
+  
+  /// List of global variables explicitly specified by the user as toc-data.
+  std::vector<std::string> TocDataVarsUserSpecified;
+
+  /// List of global variables that over-ride the toc-data default.
+  std::vector<std::string> NoTocDataVars;
+
+  /// Flag for all global variables to be treated as toc-data.
+  bool AllTocData;
 
   /// Path to allowlist file specifying which objects
   /// (files, functions) should exclusively be instrumented
diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td
index 0807d8877591a6..37e8b0ec879bb8 100644
--- a/clang/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td
@@ -587,6 +587,9 @@ def warn_drv_unsupported_gpopt : Warning<
   "ignoring '-mgpopt' option as it cannot be used with %select{|the implicit"
   " usage of }0-mabicalls">,
   InGroup<UnsupportedGPOpt>;
+def warn_drv_unsupported_tocdata: Warning<
+  "ignoring '-mtocdata' as it is only supported for -mcmodel=small">,
+  InGroup<OptionIgnored>;
 def warn_drv_unsupported_sdata : Warning<
   "ignoring '-msmall-data-limit=' with -mcmodel=large for -fpic or RV64">,
   InGroup<OptionIgnored>;
diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
index b1a282f5164a2a..b2b29dfcfe2089 100644
--- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td
+++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -94,6 +94,8 @@ def err_fe_backend_error_attr :
 def warn_fe_backend_warning_attr :
   Warning<"call to '%0' declared with 'warning' attribute: %1">, BackendInfo,
   InGroup<BackendWarningAttributes>;
+def warn_toc_unsupported_type : Warning<"The -mtocdata option is ignored "
+  "for %0 because %1.">, InGroup<BackendWarningAttributes>;
 
 def err_fe_invalid_code_complete_file : Error<
     "cannot locate code-completion file %0">, DefaultFatal;
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 95b464e7d61834..dba66eb6c3c7ce 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -3577,6 +3577,29 @@ def fpass_plugin_EQ : Joined<["-"], "fpass-plugin=">,
   MetaVarName<"<dsopath>">,
   HelpText<"Load pass plugin from a dynamic shared object file (only with new pass manager).">,
   MarshallingInfoStringVector<CodeGenOpts<"PassPlugins">>;
+def mtocdata : Flag<["-"], "mtocdata">,
+  Visibility<[ClangOption, CLOption, DXCOption, CC1Option]>,
+  Flags<[TargetSpecific]>,
+  HelpText<"All suitable variables will have the TOC data transformation applied.">,
+  MarshallingInfoFlag<CodeGenOpts<"AllTocData">>;
+def mno_tocdata : Flag<["-"], "mno-tocdata">,
+  Visibility<[ClangOption, CLOption, DXCOption, CC1Option]>,
+  Flags<[TargetSpecific]>,
+  HelpText<"This is the default. TOC data transformation is not applied to any"
+           "variables. Only variables specified explicitly in -mtocdata= will"
+           "have the TOC data transformation.">;
+def mtocdata_EQ : CommaJoined<["-"], "mtocdata=">,
+  Visibility<[ClangOption, CLOption, DXCOption, CC1Option]>,
+  Flags<[TargetSpecific]>,
+  HelpText<"Specifies a list of variables to which the TOC data transformation"
+           "will be applied.">,
+  MarshallingInfoStringVector<CodeGenOpts<"TocDataVarsUserSpecified">>;
+def mno_tocdata_EQ : CommaJoined<["-"], "mno-tocdata=">,
+  Visibility<[ClangOption, CLOption, DXCOption, CC1Option]>,
+  Flags<[TargetSpecific]>,
+  HelpText<"Specifies a list of variables to be exempt from the TOC data"
+           "transformation.">,
+  MarshallingInfoStringVector<CodeGenOpts<"NoTocDataVars">>;
 defm preserve_as_comments : BoolFOption<"preserve-as-comments",
   CodeGenOpts<"PreserveAsmComments">, DefaultTrue,
   NegFlag<SetFalse, [], [ClangOption, CC1Option],
diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp
index bbe14ef4c17244..dc42faf8dbb9fd 100644
--- a/clang/lib/CodeGen/CGDecl.cpp
+++ b/clang/lib/CodeGen/CGDecl.cpp
@@ -284,6 +284,7 @@ llvm::Constant *CodeGenModule::getOrCreateStaticVarDecl(
     setTLSMode(GV, D);
 
   setGVProperties(GV, &D);
+  getTargetCodeGenInfo().setTargetAttributes(cast<Decl>(&D), GV, *this);
 
   // Make sure the result is of the correct type.
   LangAS ExpectedAS = Ty.getAddressSpace();
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index c984260b082cd1..49af5cdfeb23d4 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -626,6 +626,28 @@ static bool checkAliasedGlobal(
   return true;
 }
 
+// Emit a warning if toc-data attribute is requested for global variables that
+// have aliases and remove the toc-data attribute.
+static void checkAliasForTocData(llvm::GlobalVariable *GVar,
+                                 const CodeGenOptions &CodeGenOpts,
+                                 DiagnosticsEngine &Diags,
+                                 SourceLocation Location) {
+  if (GVar->hasAttribute("toc-data")) {
+    auto GVId = GVar->getGlobalIdentifier();
+    // Is this a global variable specified by the user as local?
+    bool UserSpecifiedTOC =
+        llvm::binary_search(CodeGenOpts.TocDataVarsUserSpecified, GVId);
+    if (UserSpecifiedTOC) {
+      Diags.Report(Location, diag::warn_toc_unsupported_type)
+          << GVId << "the variable has an alias";
+    }
+    llvm::AttributeSet CurrAttributes = GVar->getAttributes();
+    llvm::AttributeSet NewAttributes =
+        CurrAttributes.removeAttribute(GVar->getContext(), "toc-data");
+    GVar->setAttributes(NewAttributes);
+  }
+}
+
 void CodeGenModule::checkAliases() {
   // Check if the constructed aliases are well formed. It is really unfortunate
   // that we have to do this in CodeGen, but we only construct mangled names
@@ -652,6 +674,12 @@ void CodeGenModule::checkAliases() {
       continue;
     }
 
+    if (getContext().getTargetInfo().getTriple().isOSAIX())
+      if (const llvm::GlobalVariable *GVar =
+              dyn_cast<const llvm::GlobalVariable>(GV))
+        checkAliasForTocData(const_cast<llvm::GlobalVariable *>(GVar),
+                             getCodeGenOpts(), Diags, Location);
+
     llvm::Constant *Aliasee =
         IsIFunc ? cast<llvm::GlobalIFunc>(Alias)->getResolver()
                 : cast<llvm::GlobalAlias>(Alias)->getAliasee();
diff --git a/clang/lib/CodeGen/Targets/PPC.cpp b/clang/lib/CodeGen/Targets/PPC.cpp
index 40dddde508c177..3032a9c1ee3c09 100644
--- a/clang/lib/CodeGen/Targets/PPC.cpp
+++ b/clang/lib/CodeGen/Targets/PPC.cpp
@@ -8,6 +8,7 @@
 
 #include "ABIInfoImpl.h"
 #include "TargetInfo.h"
+#include "clang/Basic/DiagnosticFrontend.h"
 
 using namespace clang;
 using namespace clang::CodeGen;
@@ -145,6 +146,9 @@ class AIXTargetCodeGenInfo : public TargetCodeGenInfo {
 
   bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
                                llvm::Value *Address) const override;
+
+  void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
+                           CodeGen::CodeGenModule &M) const override;
 };
 } // namespace
 
@@ -265,6 +269,63 @@ bool AIXTargetCodeGenInfo::initDwarfEHRegSizeTable(
   return PPC_initDwarfEHRegSizeTable(CGF, Address, Is64Bit, /*IsAIX*/ true);
 }
 
+void AIXTargetCodeGenInfo::setTargetAttributes(
+    const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &M) const {
+  if (auto *GVar = dyn_cast<llvm::GlobalVariable>(GV)) {
+    auto GVId = M.getMangledName(dyn_cast<NamedDecl>(D));
+
+    // Is this a global variable specified by the user as toc-data?
+    bool UserSpecifiedTOC =
+        llvm::binary_search(M.getCodeGenOpts().TocDataVarsUserSpecified, GVId);
+    // Assumes the same variable cannot be in both TocVarsUserSpecified and
+    // NoTocVars.
+    if (UserSpecifiedTOC ||
+        ((M.getCodeGenOpts().AllTocData) &&
+         !llvm::binary_search(M.getCodeGenOpts().NoTocDataVars, GVId))) {
+      const unsigned long PointerSize =
+          GV->getParent()->getDataLayout().getPointerSizeInBits() / 8;
+      ASTContext &Context = D->getASTContext();
+      auto *VarD = dyn_cast<VarDecl>(D);
+      assert(VarD && "Invalid declaration of global variable.");
+
+      unsigned Alignment = Context.toBits(Context.getDeclAlign(D)) / 8;
+      const auto *Ty = VarD->getType().getTypePtr();
+      const RecordDecl *RDecl =
+          Ty->isRecordType() ? Ty->getAs<RecordType>()->getDecl() : nullptr;
+
+      bool EmitDiagnostic = UserSpecifiedTOC && GV->hasExternalLinkage();
+      if (!Ty || Ty->isIncompleteType()) {
+        if (EmitDiagnostic)
+          M.getDiags().Report(D->getLocation(), diag::warn_toc_unsupported_type)
+              << GVId << "of incomplete type";
+      } else if (RDecl && RDecl->hasFlexibleArrayMember()) {
+        if (UserSpecifiedTOC)
+          M.getDiags().Report(D->getLocation(), diag::warn_toc_unsupported_type)
+              << GVId << "it contains a flexible array member";
+      } else if (VarD->getTLSKind() != VarDecl::TLS_None) {
+        if (EmitDiagnostic)
+          M.getDiags().Report(D->getLocation(), diag::warn_toc_unsupported_type)
+              << GVId << "of thread local storage model";
+      } else if (PointerSize < Context.getTypeInfo(VarD->getType()).Width / 8) {
+        if (EmitDiagnostic)
+          M.getDiags().Report(D->getLocation(), diag::warn_toc_unsupported_type)
+              << GVId << "variable is larger than a pointer";
+      } else if (PointerSize < Alignment) {
+        if (EmitDiagnostic)
+          M.getDiags().Report(D->getLocation(), diag::warn_toc_unsupported_type)
+              << GVId << "variable is aligned wider than a pointer";
+      } else if (D->hasAttr<SectionAttr>()) {
+        if (EmitDiagnostic)
+          M.getDiags().Report(D->getLocation(), diag::warn_toc_unsupported_type)
+              << GVId << "of a section attribute";
+      } else if ((GV->hasExternalLinkage() || M.getCodeGenOpts().AllTocData) &&
+                 !GV->hasInternalLinkage()) {
+        GVar->addAttribute("toc-data");
+      }
+    }
+  }
+}
+
 // PowerPC-32
 namespace {
 /// PPC32_SVR4_ABIInfo - The 32-bit PowerPC ELF (SVR4) ABI information.
diff --git a/clang/lib/Driver/ToolChains/AIX.cpp b/clang/lib/Driver/ToolChains/AIX.cpp
index e6126ff62db3c9..8bd672386e6391 100644
--- a/clang/lib/Driver/ToolChains/AIX.cpp
+++ b/clang/lib/Driver/ToolChains/AIX.cpp
@@ -435,6 +435,90 @@ void AIX::AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
   llvm_unreachable("Unexpected C++ library type; only libc++ is supported.");
 }
 
+// This function processes all the mtocdata options to build the final
+// simplified toc data options to pass to CC1.
+static void addTocDataOptions(const llvm::opt::ArgList &Args,
+                              llvm::opt::ArgStringList &CC1Args,
+                              const Driver &D) {
+
+  // Check the global toc-data setting. The default is -mno-tocdata.
+  // To enable toc-data globally, -mtocdata must be specified.
+  // Additionally, it must be last to take effect.
+  const bool TOCDataGloballyinEffect = [&Args]() {
+    if (!Args.hasArg(options::OPT_mtocdata))
+      return false;
+
+    const Arg *LastArg =
+        Args.getLastArg(options::OPT_mtocdata, options::OPT_mno_tocdata);
+    return LastArg->getOption().matches(options::OPT_mtocdata);
+  }();
+
+  // Currently only supported for small code model.
+  if (TOCDataGloballyinEffect &&
+      (Args.getLastArgValue(options::OPT_mcmodel_EQ).equals("large") ||
+       Args.getLastArgValue(options::OPT_mcmodel_EQ).equals("medium"))) {
+    D.Diag(clang::diag::warn_drv_unsupported_tocdata);
+    return;
+  }
+
+  enum TOCDataSetting {
+    AddressInTOC = 0, // Address of the symbol stored in the TOC.
+    DataInTOC = 1     // Symbol defined in the TOC.
+  };
+
+  const TOCDataSetting DefaultTocDataSetting =
+      TOCDataGloballyinEffect ? DataInTOC : AddressInTOC;
+
+  // Process the list of variables in the explicitly specified options
+  // -mtocdata= and -mno-tocdata= to see which variables are opposite to
+  // the global setting of tocdata in TOCDataGloballyinEffect.
+  // Those that have the opposite setting to TOCDataGloballyinEffect, are added
+  // to ExplicitlySpecifiedGlobals.
+  llvm::StringSet<> ExplicitlySpecifiedGlobals;
+  for (const auto Arg :
+       Args.filtered(options::OPT_mtocdata_EQ, options::OPT_mno_tocdata_EQ)) {
+    TOCDataSetting ArgTocDataSetting =
+        Arg->getOption().matches(options::OPT_mtocdata_EQ) ? DataInTOC
+                                                           : AddressInTOC;
+
+    if (ArgTocDataSetting != DefaultTocDataSetting)
+      for (const char *Val : Arg->getValues())
+        ExplicitlySpecifiedGlobals.insert(Val);
+    else
+      for (const char *Val : Arg->getValues())
+        ExplicitlySpecifiedGlobals.erase(Val);
+  }
+
+  const bool HasExplicitValues = !ExplicitlySpecifiedGlobals.empty();
+
+  auto buildExceptionList = [](const llvm::StringSet<> &ExplicitValues,
+                               const char *OptionSpelling) -> std::string {
+    std::string Option(OptionSpelling);
+    bool IsFirst = true;
+    for (const auto &E : ExplicitValues) {
+      if (!IsFirst)
+        Option += ",";
+
+      IsFirst = false;
+      Option += E.first();
+    }
+    return Option;
+  };
+
+  // Pass the final tocdata options to CC1 consisting of the default
+  // tocdata option (-mtocdata/-mno-tocdata) along with the list
+  // option (-mno-tocdata=/-mtocdata=) if there are any explicitly specified
+  // variables which would be exceptions to the default setting.
+  const char *TocDataGlobalOption =
+      TOCDataGloballyinEffect ? "-mtocdata" : "-mno-tocdata";
+  const char *TocDataListOption =
+      TOCDataGloballyinEffect ? "-mno-tocdata=" : "-mtocdata=";
+  CC1Args.push_back(TocDataGlobalOption);
+  if (HasExplicitValues)
+    CC1Args.push_back(Args.MakeArgString(llvm::Twine(
+        buildExceptionList(ExplicitlySpecifiedGlobals, TocDataListOption))));
+}
+
 void AIX::addClangTargetOptions(
     const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CC1Args,
     Action::OffloadKind DeviceOffloadingKind) const {
@@ -442,6 +526,11 @@ void AIX::addClangTargetOptions(
   Args.AddLastArg(CC1Args, options::OPT_mdefault_visibility_export_mapping_EQ);
   Args.addOptInFlag(CC1Args, options::OPT_mxcoff_roptr, options::OPT_mno_xcoff_roptr);
 
+  // Forward last mtocdata/mno_tocdata options to -cc1.
+  if (Args.hasArg(options::OPT_mtocdata_EQ, options::OPT_mno_tocdata_EQ,
+                  options::OPT_mtocdata))
+    addTocDataOptions(Args, CC1Args, getDriver());
+
   if (Args.hasFlag(options::OPT_fxl_pragma_pack,
                    options::OPT_fno_xl_pragma_pack, true))
     CC1Args.push_back("-fxl-pragma-pack");
diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp
index a25aa88bd85ef4..940610af30dceb 100644
--- a/clang/lib/Frontend/CompilerInstance.cpp
+++ b/clang/lib/Frontend/CompilerInstance.cpp
@@ -1047,6 +1047,11 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) {
   if (getFrontendOpts().ShowStats || !getFrontendOpts().StatsFile.empty())
     llvm::EnableStatistics(false);
 
+  // Sort vectors containing toc data and no toc data variables to facilitate
+  // binary search later.
+  llvm::sort(getCodeGenOpts().TocDataVarsUserSpecified);
+  llvm::sort(getCodeGenOpts().NoTocDataVars);
+
   for (const FrontendInputFile &FIF : getFrontendOpts().Inputs) {
     // Reset the ID tables if we are reusing the SourceManager and parsing
     // regular files.
diff --git a/clang/test/CodeGen/PowerPC/toc-data-attribute.c b/clang/test/CodeGen/PowerPC/toc-data-attribute.c
new file mode 100644
index 00000000000000..635ad53ce8c5d2
--- /dev/null
+++ b/clang/test/CodeGen/PowerPC/toc-data-attribute.c
@@ -0,0 +1,61 @@
+// RUN: %clang_cc1 %s -triple powerpc-ibm-aix-xcoff -S -mtocdata=f,g,h,i,j,k,l,m,n,o,p -emit-llvm -o - 2>&1 | FileCheck %s -check-prefixes=CHECK32 --match-full-lines
+// RUN: %clang_cc1 %s -triple powerpc-ibm-aix-xcoff -S -mtocdata -emit-llvm -o - 2>&1 | FileCheck %s -check-prefixes=CHECK32 --match-full-lines
+
+// RUN: %clang_cc1 %s -triple powerpc64-ibm-aix-xcoff -S -mtocdata=f,g,h,i,j,k,l,m,n,o,p -emit-llvm -o - 2>&1 | FileCheck %s -check-prefixes=CHECK64 --match-full-lines
+// RUN: %clang_cc1 %s -triple powerpc64-ibm-aix-xcoff -S -mtocdata -emit-llvm -o - 2>&1 | FileCheck %s -check-prefixes=CHECK64 --match-full-lines
+
+extern int f;
+long long g = 5;
+const char *h = "h";
+int *i;
+int __attribute__((aligned(128))) j = 0;
+float k = 100.00;
+double l = 2.5;
+int m __attribute__((section("foo"))) = 10;
+__thread int n;
+
+extern int p[];
+
+struct SomeStruct;
+extern struct SomeStruct o;
+
+static int func_a() {
+  return g+(int)h[0]+*i+j+k+l+m+n+p[0];
+}
+
+int func_b() {
+  f = 1;
+  return func_a();
+}
+
+struct SomeStruct* getAddress(void) {
+  return &o;
+}
+
+// CHECK32: @g = global i64 5, align 8
+// CHECK32: {{.*}}  = private unnamed_addr constant [2 x i8] c"h\00", align 1
+// CHECK32: @h = global {{...*}} #0
+// CHECK32: @j = global i32 0, align 128
+// CHECK32: @k = global float 1.000000e+02, align 4 #0
+// CHECK32: @l = global double 2.500000e+00, align 8
+// CHECK32: @m = global i32 10, section "foo", align 4
+// CHECK32: @f = external global i32, align 4 #0
+// CHECK32: @o = external global %struct.SomeStruct, align 1
+// CHECK32: @i = global ptr null, align 4 #0
+// CHECK32: @n = thread_local global i32 0, align 4
+// CHECK32: @p = external global [0 x i32], align 4
+// CHECK32: attributes #0 = { "toc-data" }
+
+// CHECK64: @g = global i64 5, align 8 #0
+// CHECK64: {{.*}}  = private unnamed_addr constant [2 x i8] c"h\00", align 1
+// CHECK64: @h = global {{...*}} #0
+// CHECK64: @j = global i32 0, align 128
+// CHECK64: @k = global float 1.000000e+02, align 4 #0
+// CHECK64: @l = global double 2.500000e+00, align 8 #0
+// CHECK64: @m = global i32 10, section "foo", align 4
+// CHECK64: @f = external global i32, align 4 #0
+// CHECK64: @o = external global %struct.SomeStruct, align 1
+// CHECK64: @i = global ptr null, align 8 #0
+// CHECK64: @n = thread_local global i32 0, align 4
+// CHECK64: @p = external global [0 x i32], align 4
+// CHECK64: attributes #0 = { "toc-data" }
diff --git a/clang/test/CodeGen/PowerPC/toc-data-attribute.cpp b/clang/test/CodeGen/PowerPC/toc-data-attribute.cpp
new file mode 100644
index 00000000000000..842fd05efa5c12
--- /dev/null
+++ b/clang/test/CodeGen/PowerPC/toc-data-attribute.cpp
@@ -0,0 +1,43 @@
+// RUN: %clang_cc1 %s -triple powerpc-ibm-aix-xcoff -S -mtocdata -emit-llvm -o - 2>&1 | FileCheck %s
+// RUN: %clang_cc1 %s -triple powerpc-ibm-aix-xcoff -S -mtocdata=n,_ZN11MyNamespace10myVariableE,_ZL1s,_ZZ4testvE7counter -emit-llvm -o - 2>&1 | FileCheck %s -check-prefixes=CHECKIGNORE
+// RUN: %clang_cc1 %s -triple powerpc64-ibm-aix-xcoff -S -mtocdata -emit-llvm -o - 2>&1 | FileCheck %s
+// RUN: %clang_cc1 %s -triple powerpc64-ibm-aix-xcoff -S -mtocdata=n,_ZN11MyNamespace10myVariableE,_ZL1s,_ZZ4testvE7counter -emit-llvm -o - 2>&1 | FileCheck %s -check-prefixes=CHECKIGNORE
+
+extern int n;
+static int s = 100;
+
+inline int test() {
+    static int counter = 0;
+    counter++;
+    return counter;
+}
+
+int a () {
+    n = test();
+    return 0;
+}
+
+namespace MyNamespace {
+    int myVariable = 10;
+}
+
+int b(int x) {
+    using namespace MyNamespace;
+    return x + myVariable;
+}
+
+int c(int x) {
+  s += x;
+  return s;
+}
+
+// CHECK: @n = external global i32, align 4 #0
+// CHECK: @_ZN11MyNamespace10myVariableE = global i32 10, align 4 #0
+// CHECK-NOT: @_ZL1s = internal global i32 100, align 4 #0
+// CHECK: @_ZZ4testvE7counter = linkonce_odr global i32 0, align 4 #0
+// CHECK: attributes #0 = { "toc-data" }
+// CHECKIGNORE: @n = external global i32, align 4 #0
+// CHECKIGNORE: @_ZN11MyNamespace10myVariableE = global i32 10, align 4 #0
+// CHECKIGNORE-NOT: @_ZL1s = internal global i32 100, align 4 #0
+// CHECKIGNORE-NOT: @_ZZ4testvE7counter = linkonce_odr global i32 0, align 4 #0
+// CHECKIGNORE: attributes #0 = { "toc-data" }
diff --git a/clang/test/CodeGen/PowerPC/toc-data-diagnostics.c b/clang/test/CodeGen/PowerPC/toc-data-diagnostics.c
new file mode 100644
index 00000000000000..cdf4b0cf0e05b0
--- /dev/null
+++ b/clang/test/CodeGen/PowerPC/toc-data-diagnostics.c
@@ -0,0 +1,69 @@
+// REQUIRES: powerpc-registered-target
+// RUN: %clang_cc1 %s -triple=powerpc-ibm-aix-xcoff -S -mtocdata=h,g,f,e,d,c,b,a,globalOneWithAlias,globalTwoWithAlias,ll,t3 -verify -emit-llvm -o - | FileCheck %s -check-prefix=CHECK --match-full-lines
+// RUN: %clang_cc1 %s -triple=powerpc-ibm-aix-xcoff -S -mtocdata -verify=none -emit-llvm -o - | FileCheck %s -check-prefix=CHECK --match-full-lines
+
+// none-no-diagnostics
+
+struct large_struct {
+  int x;
+  short y;
+  short z;
+  char c;
+};
+
+struct large_struct a;                      // expected-warning {{The -mtocdata option is ignored for a because variable is larger than a pointer.}}
+long long b = 5;                            // expected-warning {{The -mtocdata option is ignored for b because variable is larger than a pointer.}}
+int __attribute__((aligned(128))) c = 0;    // expected-warning {{The -mtocdata option is ignored for c because variable is aligned wider than a pointer.}}
+double d = 2.5;                             // expected-warning {{The -mtocdata option is ignored for d because variable is larger than a pointer.}}
+int e __attribute__((section("foo"))) = 10; // expected-warning {{The -mtocdata option is ignored for e because of a section attribute.}}
+__thread int f;                             // expected-warning {{The -mtocdata option is ignored for f because of thread local storage model.}}
+
+struct SomeStruct;
+extern struct SomeStruct g;                 // expected-warning {{The -mtocdata option is ignored for g because of incomplete type.}}
+
+extern int h[];                             // expected-warning {{The -mtocdata option is ignored for h because of incomplete type.}}
+
+struct ty3 {
+  int A;
+  char C[];
+};
+struct ty3 t3 = { 4, "fo" }; // expected-warning {{The -mtocdata option is ignored for t3 because it contains a flexible array member.}}
+
+int globalOneWithAlias = 10;
+__attribute__((__alias__("globalOneWithAlias"))) extern int aliasOne; // expected-warning {{The -mtocdata option is ignored for globalOneWithAlias because the variable has an alias.}}
+__attribute__((__alias__("globalTwoWithAlias"))) extern int aliasTwo; // expected-warning {{The -mtocdata option is ignored for globalTwoWithAlias because the variable has an alias.}}
+int globalTwoWithAlias = 20;
+
+
+int func() {
+  return a.x+b+c+d+e+f+h[0];
+}
+
+struct SomeStruct* getAddress(void) {
+  return &g;
+}
+
+int test() {
+  return globalOneWithAlias + globalTwoWithAlias + aliasOne + aliasTwo;
+}
+
+long long test2() {
+  static long long ll = 5;
+  ll++;
+  return ll;
+}
+
+// CHECK: @b = global i64 5, align 8
+// CHECK: @c = global i32 0, align 128
+// CHECK: @d = global double 2.500000e+00, align 8
+// CHECK: @e = global i32 10, section "foo", align 4
+// CHECK: @globalOneWithAlias = global i32 10, align 4
+// CHECK: @globalTwoWithAlias = global i32 20, align 4
+// CHECK: @a = global %struct.large_struct zeroinitializer, align 4
+// CHECK: @f = thread_local global i32 0, align 4
+// CHECK: @h = external global [0 x i32], align 4
+// CHECK: @g = external global %struct.SomeStruct, align 1 
+// CHECK: @test2.ll = internal global i64 5, align 8
+// CHECK: @aliasOne = alias i32, ptr @globalOneWithAlias
+// CHECK: @aliasTwo = alias i32, ptr @globalTwoWithAlias
+// CHECK-NOT: attributes #0 = { "toc-data" }
diff --git a/clang/test/CodeGen/PowerPC/toc-data-structs-arrays.cpp b/clang/test/CodeGen/PowerPC/toc-data-structs-arrays.cpp
new file mode 100644
index 00000000000000..6f80ede29c7c79
--- /dev/null
+++ b/clang/test/CodeGen/PowerPC/toc-data-structs-arrays.cpp
@@ -0,0 +1,64 @@
+// RUN: %clang_cc1 %s -triple powerpc-ibm-aix-xcoff -S -mtocdata=a4,a5,a8,a9,b,c,d,e,v -emit-llvm -o - 2>&1 \
+// RUN:          | FileCheck %s -check-prefixes=CHECK32 --match-full-lines
+// RUN: %clang_cc1  %s -triple powerpc-ibm-aix-xcoff -S -mtocdata -emit-llvm -o - 2>&1 \
+// RUN:          | FileCheck %s -check-prefixes=CHECK32 --match-full-lines
+
+// RUN: %clang_cc1  %s -triple powerpc64-ibm-aix-xcoff -S -mtocdata=a4,a5,a8,a9,b,c,d,e,v -emit-llvm -o - 2>&1 \
+// RUN:          | FileCheck %s -check-prefixes=CHECK64 --match-full-lines
+// RUN: %clang_cc1  %s -triple powerpc64-ibm-aix-xcoff -S -mtocdata -emit-llvm -o - 2>&1 \
+// RUN:          | FileCheck %s -check-prefixes=CHECK64 --match-full-lines
+
+struct size4_struct {
+  int x;
+};
+
+struct size5_struct {
+  int x;
+  char c;
+};
+
+struct size8_struct {
+  int x;
+  short y;
+  short z;
+};
+
+struct size9_struct {
+  int x;
+  short y;
+  short z;
+  char c;
+};
+
+struct size4_struct a4;
+struct size5_struct a5;
+struct size8_struct a8;
+struct size9_struct a9;
+
+short b[2];
+short c[3];
+short d[4];
+short e[5];
+
+int func_a() {
+  return a4.x+a5.x+a8.x+a9.x+b[0]+c[0]+d[0]+e[0];
+}
+
+// CHECK32: @a4 = global %struct.size4_struct zeroinitializer, align 4 #0
+// CHECK32: @a5 = global %struct.size5_struct zeroinitializer, align 4
+// CHECK32: @a8 = global %struct.size8_struct zeroinitializer, align 4
+// CHECK32: @a9 = global %struct.size9_struct zeroinitializer, align 4
+// CHECK32: @b = global [2 x i16] zeroinitializer, align 2 #0
+// CHECK32: @c = global [3 x i16] zeroinitializer, align 2
+// CHECK32: @d = global [4 x i16] zeroinitializer, align 2
+// CHECK32: @e = global [5 x i16] zeroinitializer, align 2
+// CHECK32: attributes #0 = { "toc-data" }
+
+// CHECK64: @a4 = global %struct.size4_struct zeroinitializer, align 4 #0
+// CHECK64: @a5 = global %struct.size5_struct zeroinitializer, align 4 #0
+// CHECK64: @a8 = global %struct.size8_struct zeroinitializer, align 4 #0
+// CHECK64: @a9 = global %struct.size9_struct zeroinitializer, align 4
+// CHECK64: @b = global [2 x i16] zeroinitializer, align 2 #0
+// CHECK64: @c = global [3 x i16] zeroinitializer, align 2 #0
+// CHECK64: @d = global [4 x i16] zeroinitializer, align 2 #0
+// CHECK64: attributes #0 = { "toc-data" }
diff --git a/clang/test/CodeGen/toc-data.c b/clang/test/CodeGen/toc-data.c
new file mode 100644
index 00000000000000..1490b9353f1f05
--- /dev/null
+++ b/clang/test/CodeGen/toc-data.c
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 %s -triple powerpc-unknown-aix -S -mtocdata=g1,g2,g3 -emit-llvm -o - | FileCheck %s -check-prefix=CHECK-MIX --match-full-lines
+// RUN: %clang_cc1 %s -triple powerpc64-unkown-aix -S -mtocdata -mno-tocdata=g4,g5 -emit-llvm -o - | FileCheck %s -check-prefix=CHECK-MIX --match-full-lines
+
+// RUN: %clang_cc1 %s -triple powerpc-unknown-aix -S -mno-tocdata -emit-llvm -o - | FileCheck %s -check-prefix=CHECK-NOTOCDATA
+// RUN: %clang_cc1 %s -triple powerpc64-unknown-aix -S -mno-tocdata -emit-llvm -o - | FileCheck %s -check-prefix=CHECK-NOTOCDATA
+
+// RUN: %clang_cc1 %s -triple powerpc-unknown-aix -S -mtocdata -emit-llvm -o - | FileCheck %s -check-prefix=CHECK-TOCDATA --match-full-lines
+// RUN: %clang_cc1 %s -triple powerpc64-unknown-aix -S -mtocdata -emit-llvm -o - | FileCheck %s -check-prefix=CHECK-TOCDATA --match-full-lines
+
+int g1, g4;
+extern int g2;
+int g3 = 0, g5 = 123;
+void func() {
+  g2 = 0;
+}
+
+// CHECK-MIX-DAG: @g3 = global i32 0, align 4 #0
+// CHECK-MIX-DAG: @g2 = external global i32, align 4 #0
+// CHECK-MIX-DAG: @g1 = global i32 0, align 4 #0
+// CHECK-MIX-DAG: @g4 = global i32 0, align 4
+// CHECK-MIX-DAG: @g5 = global i32 123, align 4
+// CHECK-MIX: attributes #0 = { "toc-data" }
+
+// CHECK-NOTOCDATA-NOT: "toc-data"
+
+// CHECK-TOCDATA-DAG: @g3 = global i32 0, align 4 #0
+// CHECK-TOCDATA-DAG: @g2 = external global i32, align 4 #0
+// CHECK-TOCDATA-DAG: @g1 = global i32 0, align 4 #0
+// CHECK-TOCDATA-DAG: @g4 = global i32 0, align 4 #0
+// CHECK-TOCDATA-DAG: @g5 = global i32 123, align 4 #0
+// CHECK-TOCDATA: attributes #0 = { "toc-data" }
diff --git a/clang/test/Driver/toc-conf.c b/clang/test/Driver/toc-conf.c
new file mode 100644
index 00000000000000..80d92ee1a90b4b
--- /dev/null
+++ b/clang/test/Driver/toc-conf.c
@@ -0,0 +1,30 @@
+// RUN: %clang %s --target=powerpc-unknown-aix -mno-tocdata -mtocdata -mno-tocdata -### 2>&1 | FileCheck %s -check-prefix=CHECK-FLAG1
+// RUN: %clang %s --target=powerpc-unknown-aix -mno-tocdata -mtocdata -mno-tocdata -mtocdata -### 2>&1 | FileCheck %s -check-prefix=CHECK-FLAG2
+// RUN: %clang %s --target=powerpc-unknown-aix -mtocdata=g1,g2 -mno-tocdata=g2 -mtocdata=g3,g4 -mno-tocdata=g5,g1 -### 2>&1 | FileCheck %s -check-prefix=CHECK-EQCONF
+// RUN: %clang %s --target=powerpc-unknown-aix -mtocdata=g1 -mtocdata -mno-tocdata -mtocdata=g2,g3 -mno-tocdata=g4,g5,g3 -### 2>&1 | FileCheck %s -check-prefix=CHECK-CONF1
+// RUN: %clang %s --target=powerpc-unknown-aix -mno-tocdata=g1 -mno-tocdata -mtocdata -### 2>&1 | FileCheck %s -check-prefix=CHECK-CONF2
+
+int g1, g4, g5;
+extern int g2;
+int g3 = 0;
+void func() {
+  g2 = 0;
+}
+
+// CHECK-FLAG1-NOT: warning:
+// CHECK-FLAG1: "-cc1"{{.*}}" "-mno-tocdata"
+
+// CHECK-FLAG2-NOT: warning:
+// CHECK-FLAG2: "-cc1"{{.*}}" "-mtocdata"
+
+// CHECK-EQCONF-NOT: warning:
+// CHECK-EQCONF: "-cc1"{{.*}}" "-mno-tocdata"
+// CHECK-EQCONF: "-mtocdata=g3,g4"
+
+// CHECK-CONF1-NOT: warning:
+// CHECK-CONF1: "-cc1"{{.*}}" "-mno-tocdata"
+// CHECK-CONF1: "-mtocdata=g2,g1"
+
+// CHECK-CONF2-NOT: warning:
+// CHECK-CONF2: "-cc1"{{.*}}" "-mtocdata"
+// CHECK-CONF2: "-mno-tocdata=g1"
diff --git a/clang/test/Driver/tocdata-cc1.c b/clang/test/Driver/tocdata-cc1.c
new file mode 100644
index 00000000000000..fe0d97ea02db1f
--- /dev/null
+++ b/clang/test/Driver/tocdata-cc1.c
@@ -0,0 +1,16 @@
+// RUN: %clang -### --target=powerpc-ibm-aix-xcoff -mcmodel=medium -mtocdata %s 2>&1 \
+// RUN:   | FileCheck -check-prefix=CHECK-NOTOC %s
+// RUN: %clang -### --target=powerpc-ibm-aix-xcoff -mcmodel=large -mtocdata %s 2>&1 \
+// RUN:   | FileCheck -check-prefix=CHECK-NOTOC %s
+// RUN: %clang -### --target=powerpc-ibm-aix-xcoff -mtocdata %s 2>&1 \
+// RUN:   | FileCheck -check-prefix=CHECK-TOC %s
+// RUN: %clang -### --target=powerpc64-ibm-aix-xcoff -mcmodel=medium -mtocdata %s 2>&1 \
+// RUN:   | FileCheck -check-prefix=CHECK-NOTOC %s
+// RUN: %clang -### --target=powerpc64-ibm-aix-xcoff -mcmodel=large -mtocdata %s 2>&1 \
+// RUN:   | FileCheck -check-prefix=CHECK-NOTOC %s
+// RUN: %clang -### --target=powerpc64-ibm-aix-xcoff -mtocdata %s 2>&1 \
+// RUN:   | FileCheck -check-prefix=CHECK-TOC %s
+// CHECK-NOTOC: warning: ignoring '-mtocdata' as it is only supported for -mcmodel=small
+// CHECK-NOTOC-NOT: "-cc1"{{.*}}" "-mtocdata"
+// CHECK-TOC: "-cc1"{{.*}}" "-mtocdata"
+// CHECK-TOC-NOT: warning: ignoring '-mtocdata' as it is only supported for -mcmodel=small
diff --git a/llvm/include/llvm/ADT/STLExtras.h b/llvm/include/llvm/ADT/STLExtras.h
index a136eeb0ff1bd7..4089771af4c67a 100644
--- a/llvm/include/llvm/ADT/STLExtras.h
+++ b/llvm/include/llvm/ADT/STLExtras.h
@@ -1945,6 +1945,19 @@ auto partition(R &&Range, UnaryPredicate P) {
   return std::partition(adl_begin(Range), adl_end(Range), P);
 }
 
+/// Provide wrappers to std::binary_search which take ranges instead of having
+/// to pass begin/end explicitly.
+template <typename R, typename T> auto binary_search(R &&Range, T &&Value) {
+  return std::binary_search(adl_begin(Range), adl_end(Range),
+                            std::forward<T>(Value));
+}
+
+template <typename R, typename T, typename Compare>
+auto binary_search(R &&Range, T &&Value, Compare C) {
+  return std::binary_search(adl_begin(Range), adl_end(Range),
+                            std::forward<T>(Value), C);
+}
+
 /// Provide wrappers to std::lower_bound which take ranges instead of having to
 /// pass begin/end explicitly.
 template <typename R, typename T> auto lower_bound(R &&Range, T &&Value) {
diff --git a/llvm/lib/MC/MCSectionXCOFF.cpp b/llvm/lib/MC/MCSectionXCOFF.cpp
index 95d32e3580e3f5..fcbf03ade221ef 100644
--- a/llvm/lib/MC/MCSectionXCOFF.cpp
+++ b/llvm/lib/MC/MCSectionXCOFF.cpp
@@ -87,8 +87,7 @@ void MCSectionXCOFF::printSwitchToSection(const MCAsmInfo &MAI, const Triple &T,
     if (getKind().isCommon() && !getKind().isBSSLocal())
       return;
 
-    assert((getKind().isBSSExtern() || getKind().isBSSLocal()) &&
-           "Unexepected section kind for toc-data");
+    assert(getKind().isBSS() && "Unexepected section kind for toc-data");
     printCsectDirective(OS);
     return;
   }
diff --git a/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp b/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp
index 9e5f0b36616d1b..ab474f481a11b7 100644
--- a/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp
+++ b/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp
@@ -535,21 +535,11 @@ static bool hasTocDataAttr(SDValue Val, unsigned PointerSize) {
   assert(GVType->isSized() && "A GlobalVariable's size must be known to be "
                               "supported by the toc data transformation.");
 
-  if (GVType->isVectorTy())
-    report_fatal_error("A GlobalVariable of Vector type is not currently "
-                       "supported by the toc data transformation.");
-
-  if (GVType->isArrayTy())
-    report_fatal_error("A GlobalVariable of Array type is not currently "
-                       "supported by the toc data transformation.");
-
-  if (GVType->isStructTy())
-    report_fatal_error("A GlobalVariable of Struct type is not currently "
-                       "supported by the toc data transformation.");
-
-  assert(GVType->getPrimitiveSizeInBits() <= PointerSize * 8 &&
-         "A GlobalVariable with size larger than a TOC entry is not currently "
-         "supported by the toc data transformation.");
+  if (GV->getParent()->getDataLayout().getTypeSizeInBits(GVType) >
+      PointerSize * 8)
+    report_fatal_error(
+        "A GlobalVariable with size larger than a TOC entry is not currently "
+        "supported by the toc data transformation.");
 
   if (GV->hasPrivateLinkage())
     report_fatal_error("A GlobalVariable with private linkage is not "
diff --git a/llvm/test/CodeGen/PowerPC/toc-data-large-array.ll b/llvm/test/CodeGen/PowerPC/toc-data-large-array.ll
new file mode 100644
index 00000000000000..90f40d9f0fec95
--- /dev/null
+++ b/llvm/test/CodeGen/PowerPC/toc-data-large-array.ll
@@ -0,0 +1,16 @@
+; RUN: not --crash llc -mtriple powerpc-ibm-aix-xcoff < %s 2>&1 | FileCheck %s --check-prefix CHECK-ERROR
+; RUN: not --crash llc -mtriple powerpc64-ibm-aix-xcoff < %s 2>&1 | FileCheck %s --check-prefix CHECK-ERROR
+
+ at a = global [5 x i16] zeroinitializer, align 2 #0
+
+; Function Attrs: noinline
+define i16 @foo() #1 {
+entry:
+  %0 = load i16, ptr @a, align 2
+  ret i16 %0
+}
+
+attributes #0 = { "toc-data" }
+attributes #1 = { noinline }
+
+; CHECK-ERROR: LLVM ERROR: A GlobalVariable with size larger than a TOC entry is not currently supported by the toc data transformation.
diff --git a/llvm/test/CodeGen/PowerPC/toc-data-struct-array.ll b/llvm/test/CodeGen/PowerPC/toc-data-struct-array.ll
new file mode 100644
index 00000000000000..7443fe96f6f2d7
--- /dev/null
+++ b/llvm/test/CodeGen/PowerPC/toc-data-struct-array.ll
@@ -0,0 +1,29 @@
+; RUN: llc -mtriple powerpc-ibm-aix-xcoff < %s | FileCheck %s --check-prefix CHECK
+; RUN: llc -mtriple powerpc64-ibm-aix-xcoff < %s | FileCheck %s --check-prefix CHECK
+
+%struct.small_struct = type { i16 }
+
+ at a = global %struct.small_struct zeroinitializer, align 2 #0
+ at b = global [2 x i16] zeroinitializer, align 2 #0
+
+; Function Attrs: noinline
+define i16 @foo() #1 {
+entry:
+  %0 = load i16, ptr @a, align 2
+  %1 = load i16, ptr @b, align 2
+  %add = add nsw i16 %0, %1
+  ret i16 %add
+}
+
+attributes #0 = { "toc-data" }
+attributes #1 = { noinline }
+
+; CHECK:      .toc
+; CHECK-NEXT: .csect a[TD],2
+; CHECK-NEXT: .globl    a[TD]                           # @a
+; CHECK-NEXT: .align    1
+; CHECK-NEXT: .space    2
+; CHECK-NEXT: .csect b[TD],2
+; CHECK-NEXT: .globl    b[TD]                           # @b
+; CHECK-NEXT: .align    1
+; CHECK-NEXT: .space    4

>From 328672f609288298357df265845aa567a4c70120 Mon Sep 17 00:00:00 2001
From: Zaara Syeda <syzaara at cpap8104.rtp.raleigh.ibm.com>
Date: Wed, 1 Nov 2023 16:20:58 -0400
Subject: [PATCH 2/9] Address review comments

---
 clang/docs/UsersManual.rst                    |   1 +
 .../clang/Basic/DiagnosticFrontendKinds.td    |   4 +-
 clang/include/clang/Driver/Options.td         |  24 ++---
 clang/lib/CodeGen/CodeGenModule.cpp           |   4 +-
 clang/lib/CodeGen/Targets/PPC.cpp             | 100 +++++++++---------
 clang/lib/Driver/ToolChains/AIX.cpp           |   9 +-
 .../CodeGen/PowerPC/toc-data-diagnostics.c    |  22 ++--
 7 files changed, 79 insertions(+), 85 deletions(-)

diff --git a/clang/docs/UsersManual.rst b/clang/docs/UsersManual.rst
index 2ce6da677e91e8..49ada3fcd5558a 100644
--- a/clang/docs/UsersManual.rst
+++ b/clang/docs/UsersManual.rst
@@ -4245,6 +4245,7 @@ Suitable variables must:
 -  not have internal linkage
 -  not have aliases
 -  not have section attributes
+-  not be thread local storage
 
 The TOC data transformation results in the variable, not its address,
 being placed in the TOC. This eliminates the need to load the address of the
diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
index b2b29dfcfe2089..8f51cd99ab5cf9 100644
--- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td
+++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -94,8 +94,8 @@ def err_fe_backend_error_attr :
 def warn_fe_backend_warning_attr :
   Warning<"call to '%0' declared with 'warning' attribute: %1">, BackendInfo,
   InGroup<BackendWarningAttributes>;
-def warn_toc_unsupported_type : Warning<"The -mtocdata option is ignored "
-  "for %0 because %1.">, InGroup<BackendWarningAttributes>;
+def warn_toc_unsupported_type : Warning<"-mtocdata option is ignored "
+  "for %0 because %1">, InGroup<BackendWarningAttributes>;
 
 def err_fe_invalid_code_complete_file : Error<
     "cannot locate code-completion file %0">, DefaultFatal;
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index dba66eb6c3c7ce..872cfae01f63b6 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -3577,25 +3577,23 @@ def fpass_plugin_EQ : Joined<["-"], "fpass-plugin=">,
   MetaVarName<"<dsopath>">,
   HelpText<"Load pass plugin from a dynamic shared object file (only with new pass manager).">,
   MarshallingInfoStringVector<CodeGenOpts<"PassPlugins">>;
-def mtocdata : Flag<["-"], "mtocdata">,
-  Visibility<[ClangOption, CLOption, DXCOption, CC1Option]>,
-  Flags<[TargetSpecific]>,
-  HelpText<"All suitable variables will have the TOC data transformation applied.">,
-  MarshallingInfoFlag<CodeGenOpts<"AllTocData">>;
-def mno_tocdata : Flag<["-"], "mno-tocdata">,
-  Visibility<[ClangOption, CLOption, DXCOption, CC1Option]>,
-  Flags<[TargetSpecific]>,
-  HelpText<"This is the default. TOC data transformation is not applied to any"
-           "variables. Only variables specified explicitly in -mtocdata= will"
-           "have the TOC data transformation.">;
+defm tocdata : BoolOption<"m","tocdata",
+  CodeGenOpts<"AllTocData">, DefaultFalse,
+  PosFlag<SetTrue, [], [ClangOption, CC1Option],
+  "All suitable variables will have the TOC data transformation applied">,
+  NegFlag<SetFalse, [], [ClangOption, CC1Option],
+  "This is the default. TOC data transformation is not applied to any"
+  "variables. Only variables specified explicitly in -mtocdata= will"
+  "have the TOC data transformation.">,
+  BothFlags<[], [ClangOption, CLOption]>>, Group<m_Group>;
 def mtocdata_EQ : CommaJoined<["-"], "mtocdata=">,
-  Visibility<[ClangOption, CLOption, DXCOption, CC1Option]>,
+  Visibility<[ClangOption, CC1Option]>,
   Flags<[TargetSpecific]>,
   HelpText<"Specifies a list of variables to which the TOC data transformation"
            "will be applied.">,
   MarshallingInfoStringVector<CodeGenOpts<"TocDataVarsUserSpecified">>;
 def mno_tocdata_EQ : CommaJoined<["-"], "mno-tocdata=">,
-  Visibility<[ClangOption, CLOption, DXCOption, CC1Option]>,
+  Visibility<[ClangOption, CC1Option]>,
   Flags<[TargetSpecific]>,
   HelpText<"Specifies a list of variables to be exempt from the TOC data"
            "transformation.">,
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 49af5cdfeb23d4..252316719e17f0 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -635,9 +635,7 @@ static void checkAliasForTocData(llvm::GlobalVariable *GVar,
   if (GVar->hasAttribute("toc-data")) {
     auto GVId = GVar->getGlobalIdentifier();
     // Is this a global variable specified by the user as local?
-    bool UserSpecifiedTOC =
-        llvm::binary_search(CodeGenOpts.TocDataVarsUserSpecified, GVId);
-    if (UserSpecifiedTOC) {
+    if ((llvm::binary_search(CodeGenOpts.TocDataVarsUserSpecified, GVId))) {
       Diags.Report(Location, diag::warn_toc_unsupported_type)
           << GVId << "the variable has an alias";
     }
diff --git a/clang/lib/CodeGen/Targets/PPC.cpp b/clang/lib/CodeGen/Targets/PPC.cpp
index 3032a9c1ee3c09..00bd3bc8d661c5 100644
--- a/clang/lib/CodeGen/Targets/PPC.cpp
+++ b/clang/lib/CodeGen/Targets/PPC.cpp
@@ -271,57 +271,55 @@ bool AIXTargetCodeGenInfo::initDwarfEHRegSizeTable(
 
 void AIXTargetCodeGenInfo::setTargetAttributes(
     const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &M) const {
-  if (auto *GVar = dyn_cast<llvm::GlobalVariable>(GV)) {
-    auto GVId = M.getMangledName(dyn_cast<NamedDecl>(D));
-
-    // Is this a global variable specified by the user as toc-data?
-    bool UserSpecifiedTOC =
-        llvm::binary_search(M.getCodeGenOpts().TocDataVarsUserSpecified, GVId);
-    // Assumes the same variable cannot be in both TocVarsUserSpecified and
-    // NoTocVars.
-    if (UserSpecifiedTOC ||
-        ((M.getCodeGenOpts().AllTocData) &&
-         !llvm::binary_search(M.getCodeGenOpts().NoTocDataVars, GVId))) {
-      const unsigned long PointerSize =
-          GV->getParent()->getDataLayout().getPointerSizeInBits() / 8;
-      ASTContext &Context = D->getASTContext();
-      auto *VarD = dyn_cast<VarDecl>(D);
-      assert(VarD && "Invalid declaration of global variable.");
-
-      unsigned Alignment = Context.toBits(Context.getDeclAlign(D)) / 8;
-      const auto *Ty = VarD->getType().getTypePtr();
-      const RecordDecl *RDecl =
-          Ty->isRecordType() ? Ty->getAs<RecordType>()->getDecl() : nullptr;
-
-      bool EmitDiagnostic = UserSpecifiedTOC && GV->hasExternalLinkage();
-      if (!Ty || Ty->isIncompleteType()) {
-        if (EmitDiagnostic)
-          M.getDiags().Report(D->getLocation(), diag::warn_toc_unsupported_type)
-              << GVId << "of incomplete type";
-      } else if (RDecl && RDecl->hasFlexibleArrayMember()) {
-        if (UserSpecifiedTOC)
-          M.getDiags().Report(D->getLocation(), diag::warn_toc_unsupported_type)
-              << GVId << "it contains a flexible array member";
-      } else if (VarD->getTLSKind() != VarDecl::TLS_None) {
-        if (EmitDiagnostic)
-          M.getDiags().Report(D->getLocation(), diag::warn_toc_unsupported_type)
-              << GVId << "of thread local storage model";
-      } else if (PointerSize < Context.getTypeInfo(VarD->getType()).Width / 8) {
-        if (EmitDiagnostic)
-          M.getDiags().Report(D->getLocation(), diag::warn_toc_unsupported_type)
-              << GVId << "variable is larger than a pointer";
-      } else if (PointerSize < Alignment) {
-        if (EmitDiagnostic)
-          M.getDiags().Report(D->getLocation(), diag::warn_toc_unsupported_type)
-              << GVId << "variable is aligned wider than a pointer";
-      } else if (D->hasAttr<SectionAttr>()) {
-        if (EmitDiagnostic)
-          M.getDiags().Report(D->getLocation(), diag::warn_toc_unsupported_type)
-              << GVId << "of a section attribute";
-      } else if ((GV->hasExternalLinkage() || M.getCodeGenOpts().AllTocData) &&
-                 !GV->hasInternalLinkage()) {
-        GVar->addAttribute("toc-data");
-      }
+  if (!isa<llvm::GlobalVariable>(GV))
+    return;
+
+  auto *GVar = dyn_cast<llvm::GlobalVariable>(GV);
+  auto GVId = M.getMangledName(dyn_cast<NamedDecl>(D));
+
+  // Is this a global variable specified by the user as toc-data?
+  bool UserSpecifiedTOC =
+      llvm::binary_search(M.getCodeGenOpts().TocDataVarsUserSpecified, GVId);
+  // Assumes the same variable cannot be in both TocVarsUserSpecified and
+  // NoTocVars.
+  if (UserSpecifiedTOC ||
+      ((M.getCodeGenOpts().AllTocData) &&
+       !llvm::binary_search(M.getCodeGenOpts().NoTocDataVars, GVId))) {
+    const unsigned long PointerSize =
+        GV->getParent()->getDataLayout().getPointerSizeInBits() / 8;
+    ASTContext &Context = D->getASTContext();
+    auto *VarD = dyn_cast<VarDecl>(D);
+    assert(VarD && "Invalid declaration of global variable.");
+
+    unsigned Alignment = Context.toBits(Context.getDeclAlign(D)) / 8;
+    const auto *Ty = VarD->getType().getTypePtr();
+    const RecordDecl *RDecl =
+        Ty->isRecordType() ? Ty->getAs<RecordType>()->getDecl() : nullptr;
+
+    bool EmitDiagnostic = UserSpecifiedTOC && GV->hasExternalLinkage();
+    auto reportUnsupportedWarning = [&](bool ShouldEmitWarning, StringRef Msg) {
+      if (ShouldEmitWarning)
+        M.getDiags().Report(D->getLocation(), diag::warn_toc_unsupported_type)
+            << GVId << Msg;
+    };
+    if (!Ty || Ty->isIncompleteType()) {
+      reportUnsupportedWarning(EmitDiagnostic, "of incomplete type");
+    } else if (RDecl && RDecl->hasFlexibleArrayMember()) {
+      reportUnsupportedWarning(EmitDiagnostic,
+                               "it contains a flexible array member");
+    } else if (VarD->getTLSKind() != VarDecl::TLS_None) {
+      reportUnsupportedWarning(EmitDiagnostic, "of thread local storage");
+    } else if (PointerSize < Context.getTypeInfo(VarD->getType()).Width / 8) {
+      reportUnsupportedWarning(EmitDiagnostic,
+                               "variable is larger than a pointer");
+    } else if (PointerSize < Alignment) {
+      reportUnsupportedWarning(EmitDiagnostic,
+                               "variable is aligned wider than a pointer");
+    } else if (D->hasAttr<SectionAttr>()) {
+      reportUnsupportedWarning(EmitDiagnostic, "of a section attribute");
+    } else if ((GV->hasExternalLinkage() || M.getCodeGenOpts().AllTocData) &&
+               !GV->hasInternalLinkage()) {
+      GVar->addAttribute("toc-data");
     }
   }
 }
diff --git a/clang/lib/Driver/ToolChains/AIX.cpp b/clang/lib/Driver/ToolChains/AIX.cpp
index 8bd672386e6391..e1c0be1f51b3e9 100644
--- a/clang/lib/Driver/ToolChains/AIX.cpp
+++ b/clang/lib/Driver/ToolChains/AIX.cpp
@@ -489,10 +489,8 @@ static void addTocDataOptions(const llvm::opt::ArgList &Args,
         ExplicitlySpecifiedGlobals.erase(Val);
   }
 
-  const bool HasExplicitValues = !ExplicitlySpecifiedGlobals.empty();
-
   auto buildExceptionList = [](const llvm::StringSet<> &ExplicitValues,
-                               const char *OptionSpelling) -> std::string {
+                               const char *OptionSpelling) {
     std::string Option(OptionSpelling);
     bool IsFirst = true;
     for (const auto &E : ExplicitValues) {
@@ -511,10 +509,11 @@ static void addTocDataOptions(const llvm::opt::ArgList &Args,
   // variables which would be exceptions to the default setting.
   const char *TocDataGlobalOption =
       TOCDataGloballyinEffect ? "-mtocdata" : "-mno-tocdata";
+  CC1Args.push_back(TocDataGlobalOption);
+
   const char *TocDataListOption =
       TOCDataGloballyinEffect ? "-mno-tocdata=" : "-mtocdata=";
-  CC1Args.push_back(TocDataGlobalOption);
-  if (HasExplicitValues)
+  if (const bool HasExplicitValues = !ExplicitlySpecifiedGlobals.empty())
     CC1Args.push_back(Args.MakeArgString(llvm::Twine(
         buildExceptionList(ExplicitlySpecifiedGlobals, TocDataListOption))));
 }
diff --git a/clang/test/CodeGen/PowerPC/toc-data-diagnostics.c b/clang/test/CodeGen/PowerPC/toc-data-diagnostics.c
index cdf4b0cf0e05b0..9d7c949c729b81 100644
--- a/clang/test/CodeGen/PowerPC/toc-data-diagnostics.c
+++ b/clang/test/CodeGen/PowerPC/toc-data-diagnostics.c
@@ -11,27 +11,27 @@ struct large_struct {
   char c;
 };
 
-struct large_struct a;                      // expected-warning {{The -mtocdata option is ignored for a because variable is larger than a pointer.}}
-long long b = 5;                            // expected-warning {{The -mtocdata option is ignored for b because variable is larger than a pointer.}}
-int __attribute__((aligned(128))) c = 0;    // expected-warning {{The -mtocdata option is ignored for c because variable is aligned wider than a pointer.}}
-double d = 2.5;                             // expected-warning {{The -mtocdata option is ignored for d because variable is larger than a pointer.}}
-int e __attribute__((section("foo"))) = 10; // expected-warning {{The -mtocdata option is ignored for e because of a section attribute.}}
-__thread int f;                             // expected-warning {{The -mtocdata option is ignored for f because of thread local storage model.}}
+struct large_struct a;                      // expected-warning {{-mtocdata option is ignored for a because variable is larger than a pointer}}
+long long b = 5;                            // expected-warning {{-mtocdata option is ignored for b because variable is larger than a pointer}}
+int __attribute__((aligned(128))) c = 0;    // expected-warning {{-mtocdata option is ignored for c because variable is aligned wider than a pointer}}
+double d = 2.5;                             // expected-warning {{-mtocdata option is ignored for d because variable is larger than a pointer}}
+int e __attribute__((section("foo"))) = 10; // expected-warning {{-mtocdata option is ignored for e because of a section attribute}}
+__thread int f;                             // expected-warning {{-mtocdata option is ignored for f because of thread local storage}}
 
 struct SomeStruct;
-extern struct SomeStruct g;                 // expected-warning {{The -mtocdata option is ignored for g because of incomplete type.}}
+extern struct SomeStruct g;                 // expected-warning {{-mtocdata option is ignored for g because of incomplete type}}
 
-extern int h[];                             // expected-warning {{The -mtocdata option is ignored for h because of incomplete type.}}
+extern int h[];                             // expected-warning {{-mtocdata option is ignored for h because of incomplete type}}
 
 struct ty3 {
   int A;
   char C[];
 };
-struct ty3 t3 = { 4, "fo" }; // expected-warning {{The -mtocdata option is ignored for t3 because it contains a flexible array member.}}
+struct ty3 t3 = { 4, "fo" }; // expected-warning {{-mtocdata option is ignored for t3 because it contains a flexible array member}}
 
 int globalOneWithAlias = 10;
-__attribute__((__alias__("globalOneWithAlias"))) extern int aliasOne; // expected-warning {{The -mtocdata option is ignored for globalOneWithAlias because the variable has an alias.}}
-__attribute__((__alias__("globalTwoWithAlias"))) extern int aliasTwo; // expected-warning {{The -mtocdata option is ignored for globalTwoWithAlias because the variable has an alias.}}
+__attribute__((__alias__("globalOneWithAlias"))) extern int aliasOne; // expected-warning {{-mtocdata option is ignored for globalOneWithAlias because the variable has an alias}}
+__attribute__((__alias__("globalTwoWithAlias"))) extern int aliasTwo; // expected-warning {{-mtocdata option is ignored for globalTwoWithAlias because the variable has an alias}}
 int globalTwoWithAlias = 20;
 
 

>From f419a847558686d3b830177d81ede78d1d79f0da Mon Sep 17 00:00:00 2001
From: Zaara Syeda <syzaara at cpap8104.rtp.raleigh.ibm.com>
Date: Tue, 28 Nov 2023 13:03:32 -0500
Subject: [PATCH 3/9] Address review comments

---
 clang/docs/UsersManual.rst                    |  4 +
 clang/lib/CodeGen/CodeGenModule.cpp           |  2 +-
 clang/lib/CodeGen/Targets/PPC.cpp             |  6 +-
 clang/lib/Driver/ToolChains/AIX.cpp           |  2 +-
 .../test/CodeGen/PowerPC/toc-data-attribute.c | 43 ++++------
 .../CodeGen/PowerPC/toc-data-attribute.cpp    | 24 +++---
 .../PowerPC/toc-data-structs-arrays.cpp       |  1 +
 clang/test/CodeGen/toc-data.c                 | 31 -------
 llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp     |  4 +-
 llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp   | 32 ++-----
 llvm/lib/Target/PowerPC/PPCSubtarget.h        | 24 ++++++
 .../CodeGen/PowerPC/toc-data-large-array2.ll  |  8 ++
 .../CodeGen/PowerPC/toc-data-struct-array.ll  | 85 +++++++++++++++++++
 13 files changed, 161 insertions(+), 105 deletions(-)
 delete mode 100644 clang/test/CodeGen/toc-data.c
 create mode 100644 llvm/test/CodeGen/PowerPC/toc-data-large-array2.ll

diff --git a/clang/docs/UsersManual.rst b/clang/docs/UsersManual.rst
index 49ada3fcd5558a..c75d85d16443d1 100644
--- a/clang/docs/UsersManual.rst
+++ b/clang/docs/UsersManual.rst
@@ -4256,6 +4256,10 @@ If the TOC data transformation is applied to a variable whose definition
 is imported, the linker will generate fixup code for reading or writing to the
 variable.
 
+When multiple toc-data options are used, the last option used has the affect.
+For example: -mno-tocdata=g5,g1 -mtocdata=g1,g2 -mno-tocdata=g2 -mtocdata=g3,g4
+results in -mtocdata=g1,g3,g4
+
 Any internal linkage variables specified to any TOC data options will be ignored.
 
 **Options:**
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 252316719e17f0..8973518172e280 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -633,7 +633,7 @@ static void checkAliasForTocData(llvm::GlobalVariable *GVar,
                                  DiagnosticsEngine &Diags,
                                  SourceLocation Location) {
   if (GVar->hasAttribute("toc-data")) {
-    auto GVId = GVar->getGlobalIdentifier();
+    auto GVId = GVar->getName();
     // Is this a global variable specified by the user as local?
     if ((llvm::binary_search(CodeGenOpts.TocDataVarsUserSpecified, GVId))) {
       Diags.Report(Location, diag::warn_toc_unsupported_type)
diff --git a/clang/lib/CodeGen/Targets/PPC.cpp b/clang/lib/CodeGen/Targets/PPC.cpp
index 00bd3bc8d661c5..44ad4dfeac6606 100644
--- a/clang/lib/CodeGen/Targets/PPC.cpp
+++ b/clang/lib/CodeGen/Targets/PPC.cpp
@@ -275,7 +275,7 @@ void AIXTargetCodeGenInfo::setTargetAttributes(
     return;
 
   auto *GVar = dyn_cast<llvm::GlobalVariable>(GV);
-  auto GVId = M.getMangledName(dyn_cast<NamedDecl>(D));
+  auto GVId = GV->getName();
 
   // Is this a global variable specified by the user as toc-data?
   bool UserSpecifiedTOC =
@@ -287,10 +287,10 @@ void AIXTargetCodeGenInfo::setTargetAttributes(
        !llvm::binary_search(M.getCodeGenOpts().NoTocDataVars, GVId))) {
     const unsigned long PointerSize =
         GV->getParent()->getDataLayout().getPointerSizeInBits() / 8;
-    ASTContext &Context = D->getASTContext();
     auto *VarD = dyn_cast<VarDecl>(D);
     assert(VarD && "Invalid declaration of global variable.");
 
+    ASTContext &Context = D->getASTContext();
     unsigned Alignment = Context.toBits(Context.getDeclAlign(D)) / 8;
     const auto *Ty = VarD->getType().getTypePtr();
     const RecordDecl *RDecl =
@@ -318,7 +318,7 @@ void AIXTargetCodeGenInfo::setTargetAttributes(
     } else if (D->hasAttr<SectionAttr>()) {
       reportUnsupportedWarning(EmitDiagnostic, "of a section attribute");
     } else if ((GV->hasExternalLinkage() || M.getCodeGenOpts().AllTocData) &&
-               !GV->hasInternalLinkage()) {
+               !GV->hasLocalLinkage()) {
       GVar->addAttribute("toc-data");
     }
   }
diff --git a/clang/lib/Driver/ToolChains/AIX.cpp b/clang/lib/Driver/ToolChains/AIX.cpp
index e1c0be1f51b3e9..c6e256c07b64a9 100644
--- a/clang/lib/Driver/ToolChains/AIX.cpp
+++ b/clang/lib/Driver/ToolChains/AIX.cpp
@@ -513,7 +513,7 @@ static void addTocDataOptions(const llvm::opt::ArgList &Args,
 
   const char *TocDataListOption =
       TOCDataGloballyinEffect ? "-mno-tocdata=" : "-mtocdata=";
-  if (const bool HasExplicitValues = !ExplicitlySpecifiedGlobals.empty())
+  if (!ExplicitlySpecifiedGlobals.empty())
     CC1Args.push_back(Args.MakeArgString(llvm::Twine(
         buildExceptionList(ExplicitlySpecifiedGlobals, TocDataListOption))));
 }
diff --git a/clang/test/CodeGen/PowerPC/toc-data-attribute.c b/clang/test/CodeGen/PowerPC/toc-data-attribute.c
index 635ad53ce8c5d2..db23d74759eeff 100644
--- a/clang/test/CodeGen/PowerPC/toc-data-attribute.c
+++ b/clang/test/CodeGen/PowerPC/toc-data-attribute.c
@@ -1,8 +1,8 @@
-// RUN: %clang_cc1 %s -triple powerpc-ibm-aix-xcoff -S -mtocdata=f,g,h,i,j,k,l,m,n,o,p -emit-llvm -o - 2>&1 | FileCheck %s -check-prefixes=CHECK32 --match-full-lines
-// RUN: %clang_cc1 %s -triple powerpc-ibm-aix-xcoff -S -mtocdata -emit-llvm -o - 2>&1 | FileCheck %s -check-prefixes=CHECK32 --match-full-lines
+// RUN: %clang_cc1 %s -triple powerpc-ibm-aix-xcoff -S -mtocdata=f,g,h,i,j,k,l,m,n,o,p -emit-llvm -o - 2>&1 | FileCheck %s -check-prefixes=COMMON,CHECK32 --match-full-lines
+// RUN: %clang_cc1 %s -triple powerpc-ibm-aix-xcoff -S -mtocdata -emit-llvm -o - 2>&1 | FileCheck %s -check-prefixes=COMMON,CHECK32 --match-full-lines
 
-// RUN: %clang_cc1 %s -triple powerpc64-ibm-aix-xcoff -S -mtocdata=f,g,h,i,j,k,l,m,n,o,p -emit-llvm -o - 2>&1 | FileCheck %s -check-prefixes=CHECK64 --match-full-lines
-// RUN: %clang_cc1 %s -triple powerpc64-ibm-aix-xcoff -S -mtocdata -emit-llvm -o - 2>&1 | FileCheck %s -check-prefixes=CHECK64 --match-full-lines
+// RUN: %clang_cc1 %s -triple powerpc64-ibm-aix-xcoff -S -mtocdata=f,g,h,i,j,k,l,m,n,o,p -emit-llvm -o - 2>&1 | FileCheck %s -check-prefixes=COMMON,CHECK64 --match-full-lines
+// RUN: %clang_cc1 %s -triple powerpc64-ibm-aix-xcoff -S -mtocdata -emit-llvm -o - 2>&1 | FileCheck %s -check-prefixes=COMMON,CHECK64 --match-full-lines
 
 extern int f;
 long long g = 5;
@@ -33,29 +33,18 @@ struct SomeStruct* getAddress(void) {
 }
 
 // CHECK32: @g = global i64 5, align 8
-// CHECK32: {{.*}}  = private unnamed_addr constant [2 x i8] c"h\00", align 1
-// CHECK32: @h = global {{...*}} #0
-// CHECK32: @j = global i32 0, align 128
-// CHECK32: @k = global float 1.000000e+02, align 4 #0
-// CHECK32: @l = global double 2.500000e+00, align 8
-// CHECK32: @m = global i32 10, section "foo", align 4
-// CHECK32: @f = external global i32, align 4 #0
-// CHECK32: @o = external global %struct.SomeStruct, align 1
-// CHECK32: @i = global ptr null, align 4 #0
-// CHECK32: @n = thread_local global i32 0, align 4
-// CHECK32: @p = external global [0 x i32], align 4
-// CHECK32: attributes #0 = { "toc-data" }
-
 // CHECK64: @g = global i64 5, align 8 #0
-// CHECK64: {{.*}}  = private unnamed_addr constant [2 x i8] c"h\00", align 1
-// CHECK64: @h = global {{...*}} #0
-// CHECK64: @j = global i32 0, align 128
-// CHECK64: @k = global float 1.000000e+02, align 4 #0
+// COMMON: {{.*}}  = private unnamed_addr constant [2 x i8] c"h\00", align 1
+// COMMON: @h = global {{...*}} #0
+// COMMON: @j = global i32 0, align 128
+// COMMON: @k = global float 1.000000e+02, align 4 #0
+// CHECK32: @l = global double 2.500000e+00, align 8
 // CHECK64: @l = global double 2.500000e+00, align 8 #0
-// CHECK64: @m = global i32 10, section "foo", align 4
-// CHECK64: @f = external global i32, align 4 #0
-// CHECK64: @o = external global %struct.SomeStruct, align 1
+// COMMON: @m = global i32 10, section "foo", align 4
+// COMMON: @f = external global i32, align 4 #0
+// COMMON: @o = external global %struct.SomeStruct, align 1
+// CHECK32: @i = global ptr null, align 4 #0
 // CHECK64: @i = global ptr null, align 8 #0
-// CHECK64: @n = thread_local global i32 0, align 4
-// CHECK64: @p = external global [0 x i32], align 4
-// CHECK64: attributes #0 = { "toc-data" }
+// COMMON: @n = thread_local global i32 0, align 4
+// COMMON: @p = external global [0 x i32], align 4
+// COMMON: attributes #0 = { "toc-data" }
diff --git a/clang/test/CodeGen/PowerPC/toc-data-attribute.cpp b/clang/test/CodeGen/PowerPC/toc-data-attribute.cpp
index 842fd05efa5c12..8183e3b727e7b3 100644
--- a/clang/test/CodeGen/PowerPC/toc-data-attribute.cpp
+++ b/clang/test/CodeGen/PowerPC/toc-data-attribute.cpp
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 %s -triple powerpc-ibm-aix-xcoff -S -mtocdata -emit-llvm -o - 2>&1 | FileCheck %s
-// RUN: %clang_cc1 %s -triple powerpc-ibm-aix-xcoff -S -mtocdata=n,_ZN11MyNamespace10myVariableE,_ZL1s,_ZZ4testvE7counter -emit-llvm -o - 2>&1 | FileCheck %s -check-prefixes=CHECKIGNORE
-// RUN: %clang_cc1 %s -triple powerpc64-ibm-aix-xcoff -S -mtocdata -emit-llvm -o - 2>&1 | FileCheck %s
-// RUN: %clang_cc1 %s -triple powerpc64-ibm-aix-xcoff -S -mtocdata=n,_ZN11MyNamespace10myVariableE,_ZL1s,_ZZ4testvE7counter -emit-llvm -o - 2>&1 | FileCheck %s -check-prefixes=CHECKIGNORE
+// RUN: %clang_cc1 %s -triple powerpc-ibm-aix-xcoff -S -mtocdata -emit-llvm -o - 2>&1 | FileCheck %s -check-prefixes=COMMON,ALLTOC
+// RUN: %clang_cc1 %s -triple powerpc-ibm-aix-xcoff -S -mtocdata=n,_ZN11MyNamespace10myVariableE,_ZL1s,_ZZ4testvE7counter -emit-llvm -o - 2>&1 | FileCheck %s -check-prefixes=COMMON,TOCLIST
+// RUN: %clang_cc1 %s -triple powerpc64-ibm-aix-xcoff -S -mtocdata -emit-llvm -o - 2>&1 | FileCheck %s -check-prefixes=COMMON,ALLTOC
+// RUN: %clang_cc1 %s -triple powerpc64-ibm-aix-xcoff -S -mtocdata=n,_ZN11MyNamespace10myVariableE,_ZL1s,_ZZ4testvE7counter -emit-llvm -o - 2>&1 | FileCheck %s -check-prefixes=COMMON,TOCLIST
 
 extern int n;
 static int s = 100;
@@ -31,13 +31,9 @@ int c(int x) {
   return s;
 }
 
-// CHECK: @n = external global i32, align 4 #0
-// CHECK: @_ZN11MyNamespace10myVariableE = global i32 10, align 4 #0
-// CHECK-NOT: @_ZL1s = internal global i32 100, align 4 #0
-// CHECK: @_ZZ4testvE7counter = linkonce_odr global i32 0, align 4 #0
-// CHECK: attributes #0 = { "toc-data" }
-// CHECKIGNORE: @n = external global i32, align 4 #0
-// CHECKIGNORE: @_ZN11MyNamespace10myVariableE = global i32 10, align 4 #0
-// CHECKIGNORE-NOT: @_ZL1s = internal global i32 100, align 4 #0
-// CHECKIGNORE-NOT: @_ZZ4testvE7counter = linkonce_odr global i32 0, align 4 #0
-// CHECKIGNORE: attributes #0 = { "toc-data" }
+// COMMON: @n = external global i32, align 4 #0
+// COMMON: @_ZN11MyNamespace10myVariableE = global i32 10, align 4 #0
+// COMMON-NOT: @_ZL1s = internal global i32 100, align 4 #0
+// ALLTOC: @_ZZ4testvE7counter = linkonce_odr global i32 0, align 4 #0
+// TOCLIST-NOT: @_ZZ4testvE7counter = linkonce_odr global i32 0, align 4 #0
+// COMMON: attributes #0 = { "toc-data" }
diff --git a/clang/test/CodeGen/PowerPC/toc-data-structs-arrays.cpp b/clang/test/CodeGen/PowerPC/toc-data-structs-arrays.cpp
index 6f80ede29c7c79..a717995cdceb19 100644
--- a/clang/test/CodeGen/PowerPC/toc-data-structs-arrays.cpp
+++ b/clang/test/CodeGen/PowerPC/toc-data-structs-arrays.cpp
@@ -61,4 +61,5 @@ int func_a() {
 // CHECK64: @b = global [2 x i16] zeroinitializer, align 2 #0
 // CHECK64: @c = global [3 x i16] zeroinitializer, align 2 #0
 // CHECK64: @d = global [4 x i16] zeroinitializer, align 2 #0
+// CHECK64: @e = global [5 x i16] zeroinitializer, align 2
 // CHECK64: attributes #0 = { "toc-data" }
diff --git a/clang/test/CodeGen/toc-data.c b/clang/test/CodeGen/toc-data.c
deleted file mode 100644
index 1490b9353f1f05..00000000000000
--- a/clang/test/CodeGen/toc-data.c
+++ /dev/null
@@ -1,31 +0,0 @@
-// RUN: %clang_cc1 %s -triple powerpc-unknown-aix -S -mtocdata=g1,g2,g3 -emit-llvm -o - | FileCheck %s -check-prefix=CHECK-MIX --match-full-lines
-// RUN: %clang_cc1 %s -triple powerpc64-unkown-aix -S -mtocdata -mno-tocdata=g4,g5 -emit-llvm -o - | FileCheck %s -check-prefix=CHECK-MIX --match-full-lines
-
-// RUN: %clang_cc1 %s -triple powerpc-unknown-aix -S -mno-tocdata -emit-llvm -o - | FileCheck %s -check-prefix=CHECK-NOTOCDATA
-// RUN: %clang_cc1 %s -triple powerpc64-unknown-aix -S -mno-tocdata -emit-llvm -o - | FileCheck %s -check-prefix=CHECK-NOTOCDATA
-
-// RUN: %clang_cc1 %s -triple powerpc-unknown-aix -S -mtocdata -emit-llvm -o - | FileCheck %s -check-prefix=CHECK-TOCDATA --match-full-lines
-// RUN: %clang_cc1 %s -triple powerpc64-unknown-aix -S -mtocdata -emit-llvm -o - | FileCheck %s -check-prefix=CHECK-TOCDATA --match-full-lines
-
-int g1, g4;
-extern int g2;
-int g3 = 0, g5 = 123;
-void func() {
-  g2 = 0;
-}
-
-// CHECK-MIX-DAG: @g3 = global i32 0, align 4 #0
-// CHECK-MIX-DAG: @g2 = external global i32, align 4 #0
-// CHECK-MIX-DAG: @g1 = global i32 0, align 4 #0
-// CHECK-MIX-DAG: @g4 = global i32 0, align 4
-// CHECK-MIX-DAG: @g5 = global i32 123, align 4
-// CHECK-MIX: attributes #0 = { "toc-data" }
-
-// CHECK-NOTOCDATA-NOT: "toc-data"
-
-// CHECK-TOCDATA-DAG: @g3 = global i32 0, align 4 #0
-// CHECK-TOCDATA-DAG: @g2 = external global i32, align 4 #0
-// CHECK-TOCDATA-DAG: @g1 = global i32 0, align 4 #0
-// CHECK-TOCDATA-DAG: @g4 = global i32 0, align 4 #0
-// CHECK-TOCDATA-DAG: @g5 = global i32 123, align 4 #0
-// CHECK-TOCDATA: attributes #0 = { "toc-data" }
diff --git a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
index 483cd788ebfe0c..5deeb1bbd43f5d 100644
--- a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
+++ b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
@@ -2629,7 +2629,9 @@ void PPCAIXAsmPrinter::emitGlobalVariable(const GlobalVariable *GV) {
   // If the Global Variable has the toc-data attribute, it needs to be emitted
   // when we emit the .toc section.
   if (GV->hasAttribute("toc-data")) {
-    TOCDataGlobalVars.push_back(GV);
+    unsigned PointerSize = GV->getParent()->getDataLayout().getPointerSize();
+    if (Subtarget->tocDataChecks(PointerSize, GV))
+      TOCDataGlobalVars.push_back(GV);
     return;
   }
 
diff --git a/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp b/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp
index ab474f481a11b7..236c54233b87f2 100644
--- a/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp
+++ b/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp
@@ -510,7 +510,8 @@ SDNode *PPCDAGToDAGISel::getGlobalBaseReg() {
 }
 
 // Check if a SDValue has the toc-data attribute.
-static bool hasTocDataAttr(SDValue Val, unsigned PointerSize) {
+static bool hasTocDataAttr(SDValue Val, unsigned PointerSize,
+                           const PPCSubtarget *Subtarget) {
   GlobalAddressSDNode *GA = dyn_cast<GlobalAddressSDNode>(Val);
   if (!GA)
     return false;
@@ -522,30 +523,7 @@ static bool hasTocDataAttr(SDValue Val, unsigned PointerSize) {
   if (!GV->hasAttribute("toc-data"))
     return false;
 
-  // TODO: These asserts should be updated as more support for the toc data
-  // transformation is added (struct support, etc.).
-
-  assert(
-      PointerSize >= GV->getAlign().valueOrOne().value() &&
-      "GlobalVariables with an alignment requirement stricter than TOC entry "
-      "size not supported by the toc data transformation.");
-
-  Type *GVType = GV->getValueType();
-
-  assert(GVType->isSized() && "A GlobalVariable's size must be known to be "
-                              "supported by the toc data transformation.");
-
-  if (GV->getParent()->getDataLayout().getTypeSizeInBits(GVType) >
-      PointerSize * 8)
-    report_fatal_error(
-        "A GlobalVariable with size larger than a TOC entry is not currently "
-        "supported by the toc data transformation.");
-
-  if (GV->hasPrivateLinkage())
-    report_fatal_error("A GlobalVariable with private linkage is not "
-                       "currently supported by the toc data transformation.");
-
-  return true;
+  return Subtarget->tocDataChecks(PointerSize, GV);
 }
 
 /// isInt32Immediate - This method tests to see if the node is a 32-bit constant
@@ -6121,7 +6099,7 @@ void PPCDAGToDAGISel::Select(SDNode *N) {
       assert(isAIXABI && "ELF ABI already handled");
 
       if (hasTocDataAttr(N->getOperand(0),
-                         CurDAG->getDataLayout().getPointerSize())) {
+                         CurDAG->getDataLayout().getPointerSize(), Subtarget)) {
         replaceWith(PPC::ADDItoc, N, MVT::i32);
         return;
       }
@@ -6134,7 +6112,7 @@ void PPCDAGToDAGISel::Select(SDNode *N) {
       assert(isAIXABI && "ELF ABI handled in common SelectCode");
 
       if (hasTocDataAttr(N->getOperand(0),
-                         CurDAG->getDataLayout().getPointerSize())) {
+                         CurDAG->getDataLayout().getPointerSize(), Subtarget)) {
         replaceWith(PPC::ADDItoc8, N, MVT::i64);
         return;
       }
diff --git a/llvm/lib/Target/PowerPC/PPCSubtarget.h b/llvm/lib/Target/PowerPC/PPCSubtarget.h
index 306a52dca8362b..07dc280d8288b9 100644
--- a/llvm/lib/Target/PowerPC/PPCSubtarget.h
+++ b/llvm/lib/Target/PowerPC/PPCSubtarget.h
@@ -245,6 +245,30 @@ class PPCSubtarget : public PPCGenSubtargetInfo {
   /// True if the GV will be accessed via an indirect symbol.
   bool isGVIndirectSymbol(const GlobalValue *GV) const;
 
+  bool tocDataChecks(unsigned PointerSize, const GlobalVariable *GV) const {
+    // TODO: These asserts should be updated as more support for the toc data
+    // transformation is added (struct support, etc.).
+    assert(
+        PointerSize >= GV->getAlign().valueOrOne().value() &&
+        "GlobalVariables with an alignment requirement stricter than TOC entry "
+        "size not supported by the toc data transformation.");
+
+    Type *GVType = GV->getValueType();
+    assert(GVType->isSized() && "A GlobalVariable's size must be known to be "
+                                "supported by the toc data transformation.");
+    if (GV->getParent()->getDataLayout().getTypeSizeInBits(GVType) >
+        PointerSize * 8)
+      report_fatal_error(
+          "A GlobalVariable with size larger than a TOC entry is not currently "
+          "supported by the toc data transformation.");
+    if (GV->hasLocalLinkage() || GV->hasPrivateLinkage())
+      report_fatal_error(
+          "A GlobalVariable with private or local linkage is not "
+          "currently supported by the toc data transformation.");
+    assert(!GV->hasCommonLinkage() &&
+           "Tentative definitions cannot have the mapping class XMC_TD.");
+    return true;
+  }
   /// True if the ABI is descriptor based.
   bool usesFunctionDescriptors() const {
     // Both 32-bit and 64-bit AIX are descriptor based. For ELF only the 64-bit
diff --git a/llvm/test/CodeGen/PowerPC/toc-data-large-array2.ll b/llvm/test/CodeGen/PowerPC/toc-data-large-array2.ll
new file mode 100644
index 00000000000000..f870e996a40192
--- /dev/null
+++ b/llvm/test/CodeGen/PowerPC/toc-data-large-array2.ll
@@ -0,0 +1,8 @@
+; RUN: not --crash llc -mtriple powerpc-ibm-aix-xcoff < %s 2>&1 | FileCheck %s --check-prefix CHECK-ERROR
+; RUN: not --crash llc -mtriple powerpc64-ibm-aix-xcoff < %s 2>&1 | FileCheck %s --check-prefix CHECK-ERROR
+
+ at a = global [5 x i16] zeroinitializer, align 2 #0
+
+attributes #0 = { "toc-data" }
+
+; CHECK-ERROR: LLVM ERROR: A GlobalVariable with size larger than a TOC entry is not currently supported by the toc data transformation.
diff --git a/llvm/test/CodeGen/PowerPC/toc-data-struct-array.ll b/llvm/test/CodeGen/PowerPC/toc-data-struct-array.ll
index 7443fe96f6f2d7..5a1f1438e33d45 100644
--- a/llvm/test/CodeGen/PowerPC/toc-data-struct-array.ll
+++ b/llvm/test/CodeGen/PowerPC/toc-data-struct-array.ll
@@ -1,6 +1,11 @@
 ; RUN: llc -mtriple powerpc-ibm-aix-xcoff < %s | FileCheck %s --check-prefix CHECK
 ; RUN: llc -mtriple powerpc64-ibm-aix-xcoff < %s | FileCheck %s --check-prefix CHECK
 
+; RUN: llc -filetype=obj -mtriple powerpc-ibm-aix-xcoff < %s -o %t32.o
+; RUN: llvm-readobj %t32.o --syms | FileCheck %s --check-prefix=OBJ32
+; RUN: llc -filetype=obj -mtriple powerpc64-ibm-aix-xcoff < %s -o %t64.o
+; RUN: llvm-readobj %t64.o --syms | FileCheck %s --check-prefix=OBJ64
+
 %struct.small_struct = type { i16 }
 
 @a = global %struct.small_struct zeroinitializer, align 2 #0
@@ -27,3 +32,83 @@ attributes #1 = { noinline }
 ; CHECK-NEXT: .globl    b[TD]                           # @b
 ; CHECK-NEXT: .align    1
 ; CHECK-NEXT: .space    4
+
+; OBJ32:  Symbol {
+; OBJ32:    Index: 9
+; OBJ32-NEXT:    Name: a
+; OBJ32-NEXT:    Value (RelocatableAddress): 0x3C
+; OBJ32-NEXT:    Section: .data
+; OBJ32-NEXT:    Type: 0x0
+; OBJ32-NEXT:    StorageClass: C_EXT (0x2)
+; OBJ32-NEXT:    NumberOfAuxEntries: 1
+; OBJ32-NEXT:    CSECT Auxiliary Entry {
+; OBJ32-NEXT:      Index: 10
+; OBJ32-NEXT:      SectionLen: 2
+; OBJ32-NEXT:      ParameterHashIndex: 0x0
+; OBJ32-NEXT:      TypeChkSectNum: 0x0
+; OBJ32-NEXT:      SymbolAlignmentLog2: 2
+; OBJ32-NEXT:      SymbolType: XTY_SD (0x1)
+; OBJ32-NEXT:      StorageMappingClass: XMC_TD (0x10)
+; OBJ32-NEXT:      StabInfoIndex: 0x0
+; OBJ32-NEXT:      StabSectNum: 0x0
+; OBJ32-NEXT:    }
+; OBJ32-NEXT:  }
+; OBJ32-NEXT:  Symbol {
+; OBJ32-NEXT:    Index: 11
+; OBJ32-NEXT:    Name: b
+; OBJ32-NEXT:    Value (RelocatableAddress): 0x40
+; OBJ32-NEXT:    Section: .data
+; OBJ32-NEXT:    Type: 0x0
+; OBJ32-NEXT:    StorageClass: C_EXT (0x2)
+; OBJ32-NEXT:    NumberOfAuxEntries: 1
+; OBJ32-NEXT:    CSECT Auxiliary Entry {
+; OBJ32-NEXT:      Index: 12
+; OBJ32-NEXT:      SectionLen: 4
+; OBJ32-NEXT:      ParameterHashIndex: 0x0
+; OBJ32-NEXT:      TypeChkSectNum: 0x0
+; OBJ32-NEXT:      SymbolAlignmentLog2: 2
+; OBJ32-NEXT:      SymbolType: XTY_SD (0x1)
+; OBJ32-NEXT:      StorageMappingClass: XMC_TD (0x10)
+; OBJ32-NEXT:      StabInfoIndex: 0x0
+; OBJ32-NEXT:      StabSectNum: 0x0
+; OBJ32-NEXT:    }
+; OBJ32-NEXT:  }
+
+; OBJ64:  Symbol {
+; OBJ64:    Index: 9
+; OBJ64-NEXT:    Name: a
+; OBJ64-NEXT:    Value (RelocatableAddress): 0x48
+; OBJ64-NEXT:    Section: .data
+; OBJ64-NEXT:    Type: 0x0
+; OBJ64-NEXT:    StorageClass: C_EXT (0x2)
+; OBJ64-NEXT:    NumberOfAuxEntries: 1
+; OBJ64-NEXT:    CSECT Auxiliary Entry {
+; OBJ64-NEXT:      Index: 10
+; OBJ64-NEXT:      SectionLen: 2
+; OBJ64-NEXT:      ParameterHashIndex: 0x0
+; OBJ64-NEXT:      TypeChkSectNum: 0x0
+; OBJ64-NEXT:      SymbolAlignmentLog2: 2
+; OBJ64-NEXT:      SymbolType: XTY_SD (0x1)
+; OBJ64-NEXT:      StorageMappingClass: XMC_TD (0x10)
+; OBJ64-NEXT:      Auxiliary Type: AUX_CSECT (0xFB)
+; OBJ64-NEXT:    }
+; OBJ64-NEXT:  }
+; OBJ64-NEXT:  Symbol {
+; OBJ64-NEXT:    Index: 11
+; OBJ64-NEXT:    Name: b
+; OBJ64-NEXT:    Value (RelocatableAddress): 0x4C
+; OBJ64-NEXT:    Section: .data
+; OBJ64-NEXT:    Type: 0x0
+; OBJ64-NEXT:    StorageClass: C_EXT (0x2)
+; OBJ64-NEXT:    NumberOfAuxEntries: 1
+; OBJ64-NEXT:    CSECT Auxiliary Entry {
+; OBJ64-NEXT:      Index: 12
+; OBJ64-NEXT:      SectionLen: 4
+; OBJ64-NEXT:      ParameterHashIndex: 0x0
+; OBJ64-NEXT:      TypeChkSectNum: 0x0
+; OBJ64-NEXT:      SymbolAlignmentLog2: 2
+; OBJ64-NEXT:      SymbolType: XTY_SD (0x1)
+; OBJ64-NEXT:      StorageMappingClass: XMC_TD (0x10)
+; OBJ64-NEXT:      Auxiliary Type: AUX_CSECT (0xFB)
+; OBJ64-NEXT:    }
+; OBJ64-NEXT:  }

>From bade9e8fb6a09ef273ca5ec1236d36cf2a761c1b Mon Sep 17 00:00:00 2001
From: Zaara Syeda <syzaara at cpap8104.rtp.raleigh.ibm.com>
Date: Thu, 30 Nov 2023 10:41:12 -0500
Subject: [PATCH 4/9] Address review comments

---
 clang/docs/UsersManual.rst                 | 2 +-
 clang/include/clang/Basic/CodeGenOptions.h | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang/docs/UsersManual.rst b/clang/docs/UsersManual.rst
index c75d85d16443d1..403d471f1c84fd 100644
--- a/clang/docs/UsersManual.rst
+++ b/clang/docs/UsersManual.rst
@@ -4260,7 +4260,7 @@ When multiple toc-data options are used, the last option used has the affect.
 For example: -mno-tocdata=g5,g1 -mtocdata=g1,g2 -mno-tocdata=g2 -mtocdata=g3,g4
 results in -mtocdata=g1,g3,g4
 
-Any internal linkage variables specified to any TOC data options will be ignored.
+Name of variables not having external linkage will be ignored.
 
 **Options:**
 
diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h
index ecf3914228d92b..cf29e576ef3209 100644
--- a/clang/include/clang/Basic/CodeGenOptions.h
+++ b/clang/include/clang/Basic/CodeGenOptions.h
@@ -403,7 +403,7 @@ class CodeGenOptions : public CodeGenOptionsBase {
 
   /// List of pass builder callbacks.
   std::vector<std::function<void(llvm::PassBuilder &)>> PassBuilderCallbacks;
-  
+
   /// List of global variables explicitly specified by the user as toc-data.
   std::vector<std::string> TocDataVarsUserSpecified;
 

>From d725ee8a5631c02816d7f75545b06b289fc85eb3 Mon Sep 17 00:00:00 2001
From: Zaara Syeda <syzaara at cpap8104.rtp.raleigh.ibm.com>
Date: Thu, 30 Nov 2023 10:43:57 -0500
Subject: [PATCH 5/9] Fix grammer

---
 clang/docs/UsersManual.rst | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/docs/UsersManual.rst b/clang/docs/UsersManual.rst
index 403d471f1c84fd..7a63d720241a7a 100644
--- a/clang/docs/UsersManual.rst
+++ b/clang/docs/UsersManual.rst
@@ -4260,7 +4260,7 @@ When multiple toc-data options are used, the last option used has the affect.
 For example: -mno-tocdata=g5,g1 -mtocdata=g1,g2 -mno-tocdata=g2 -mtocdata=g3,g4
 results in -mtocdata=g1,g3,g4
 
-Name of variables not having external linkage will be ignored.
+Names of variables not having external linkage will be ignored.
 
 **Options:**
 

>From 267c480af459a4280b982f3e678a645b7e383d23 Mon Sep 17 00:00:00 2001
From: Zaara Syeda <syzaara at cpap8104.rtp.raleigh.ibm.com>
Date: Thu, 18 Jan 2024 15:53:15 -0500
Subject: [PATCH 6/9] Address review

---
 clang/lib/CodeGen/Targets/PPC.cpp             |  7 ++---
 clang/lib/Driver/ToolChains/AIX.cpp           |  9 +++----
 .../CodeGen/PowerPC/toc-data-diagnostics.c    |  3 +--
 llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp     |  4 +--
 llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp   |  3 +--
 llvm/lib/Target/PowerPC/PPCSubtarget.cpp      | 24 +++++++++++++++++
 llvm/lib/Target/PowerPC/PPCSubtarget.h        | 26 ++-----------------
 7 files changed, 38 insertions(+), 38 deletions(-)

diff --git a/clang/lib/CodeGen/Targets/PPC.cpp b/clang/lib/CodeGen/Targets/PPC.cpp
index 44ad4dfeac6606..6d9c979b0142e8 100644
--- a/clang/lib/CodeGen/Targets/PPC.cpp
+++ b/clang/lib/CodeGen/Targets/PPC.cpp
@@ -316,9 +316,10 @@ void AIXTargetCodeGenInfo::setTargetAttributes(
       reportUnsupportedWarning(EmitDiagnostic,
                                "variable is aligned wider than a pointer");
     } else if (D->hasAttr<SectionAttr>()) {
-      reportUnsupportedWarning(EmitDiagnostic, "of a section attribute");
-    } else if ((GV->hasExternalLinkage() || M.getCodeGenOpts().AllTocData) &&
-               !GV->hasLocalLinkage()) {
+      reportUnsupportedWarning(EmitDiagnostic,
+                               "variable has a section attribute");
+    } else if (GV->hasExternalLinkage() ||
+               (M.getCodeGenOpts().AllTocData && !GV->hasLocalLinkage())) {
       GVar->addAttribute("toc-data");
     }
   }
diff --git a/clang/lib/Driver/ToolChains/AIX.cpp b/clang/lib/Driver/ToolChains/AIX.cpp
index c6e256c07b64a9..8329da61414c51 100644
--- a/clang/lib/Driver/ToolChains/AIX.cpp
+++ b/clang/lib/Driver/ToolChains/AIX.cpp
@@ -445,12 +445,11 @@ static void addTocDataOptions(const llvm::opt::ArgList &Args,
   // To enable toc-data globally, -mtocdata must be specified.
   // Additionally, it must be last to take effect.
   const bool TOCDataGloballyinEffect = [&Args]() {
-    if (!Args.hasArg(options::OPT_mtocdata))
+    if (const Arg *LastArg =
+            Args.getLastArg(options::OPT_mtocdata, options::OPT_mno_tocdata))
+      return LastArg->getOption().matches(options::OPT_mtocdata);
+    else
       return false;
-
-    const Arg *LastArg =
-        Args.getLastArg(options::OPT_mtocdata, options::OPT_mno_tocdata);
-    return LastArg->getOption().matches(options::OPT_mtocdata);
   }();
 
   // Currently only supported for small code model.
diff --git a/clang/test/CodeGen/PowerPC/toc-data-diagnostics.c b/clang/test/CodeGen/PowerPC/toc-data-diagnostics.c
index 9d7c949c729b81..ba8955530e4670 100644
--- a/clang/test/CodeGen/PowerPC/toc-data-diagnostics.c
+++ b/clang/test/CodeGen/PowerPC/toc-data-diagnostics.c
@@ -1,4 +1,3 @@
-// REQUIRES: powerpc-registered-target
 // RUN: %clang_cc1 %s -triple=powerpc-ibm-aix-xcoff -S -mtocdata=h,g,f,e,d,c,b,a,globalOneWithAlias,globalTwoWithAlias,ll,t3 -verify -emit-llvm -o - | FileCheck %s -check-prefix=CHECK --match-full-lines
 // RUN: %clang_cc1 %s -triple=powerpc-ibm-aix-xcoff -S -mtocdata -verify=none -emit-llvm -o - | FileCheck %s -check-prefix=CHECK --match-full-lines
 
@@ -15,7 +14,7 @@ struct large_struct a;                      // expected-warning {{-mtocdata opti
 long long b = 5;                            // expected-warning {{-mtocdata option is ignored for b because variable is larger than a pointer}}
 int __attribute__((aligned(128))) c = 0;    // expected-warning {{-mtocdata option is ignored for c because variable is aligned wider than a pointer}}
 double d = 2.5;                             // expected-warning {{-mtocdata option is ignored for d because variable is larger than a pointer}}
-int e __attribute__((section("foo"))) = 10; // expected-warning {{-mtocdata option is ignored for e because of a section attribute}}
+int e __attribute__((section("foo"))) = 10; // expected-warning {{-mtocdata option is ignored for e because variable has a section attribute}}
 __thread int f;                             // expected-warning {{-mtocdata option is ignored for f because of thread local storage}}
 
 struct SomeStruct;
diff --git a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
index 5deeb1bbd43f5d..189f1346d82b59 100644
--- a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
+++ b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
@@ -2630,8 +2630,8 @@ void PPCAIXAsmPrinter::emitGlobalVariable(const GlobalVariable *GV) {
   // when we emit the .toc section.
   if (GV->hasAttribute("toc-data")) {
     unsigned PointerSize = GV->getParent()->getDataLayout().getPointerSize();
-    if (Subtarget->tocDataChecks(PointerSize, GV))
-      TOCDataGlobalVars.push_back(GV);
+    Subtarget->tocDataChecks(PointerSize, GV);
+    TOCDataGlobalVars.push_back(GV);
     return;
   }
 
diff --git a/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp b/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp
index 236c54233b87f2..44c4134388ea5d 100644
--- a/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp
+++ b/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp
@@ -522,8 +522,7 @@ static bool hasTocDataAttr(SDValue Val, unsigned PointerSize,
 
   if (!GV->hasAttribute("toc-data"))
     return false;
-
-  return Subtarget->tocDataChecks(PointerSize, GV);
+  return true;
 }
 
 /// isInt32Immediate - This method tests to see if the node is a 32-bit constant
diff --git a/llvm/lib/Target/PowerPC/PPCSubtarget.cpp b/llvm/lib/Target/PowerPC/PPCSubtarget.cpp
index 2735bdee3bcfcc..becbbe125bd9fd 100644
--- a/llvm/lib/Target/PowerPC/PPCSubtarget.cpp
+++ b/llvm/lib/Target/PowerPC/PPCSubtarget.cpp
@@ -185,6 +185,30 @@ bool PPCSubtarget::enableSubRegLiveness() const {
   return UseSubRegLiveness;
 }
 
+void PPCSubtarget::tocDataChecks(unsigned PointerSize,
+                                 const GlobalVariable *GV) const {
+  // TODO: These asserts should be updated as more support for the toc data
+  // transformation is added (struct support, etc.).
+  assert(
+      PointerSize >= GV->getAlign().valueOrOne().value() &&
+      "GlobalVariables with an alignment requirement stricter than TOC entry "
+      "size not supported by the toc data transformation.");
+
+  Type *GVType = GV->getValueType();
+  assert(GVType->isSized() && "A GlobalVariable's size must be known to be "
+                              "supported by the toc data transformation.");
+  if (GV->getParent()->getDataLayout().getTypeSizeInBits(GVType) >
+      PointerSize * 8)
+    report_fatal_error(
+        "A GlobalVariable with size larger than a TOC entry is not currently "
+        "supported by the toc data transformation.");
+  if (GV->hasLocalLinkage() || GV->hasPrivateLinkage())
+    report_fatal_error("A GlobalVariable with private or local linkage is not "
+                       "currently supported by the toc data transformation.");
+  assert(!GV->hasCommonLinkage() &&
+         "Tentative definitions cannot have the mapping class XMC_TD.");
+}
+
 bool PPCSubtarget::isGVIndirectSymbol(const GlobalValue *GV) const {
   // Large code model always uses the TOC even for local symbols.
   if (TM.getCodeModel() == CodeModel::Large)
diff --git a/llvm/lib/Target/PowerPC/PPCSubtarget.h b/llvm/lib/Target/PowerPC/PPCSubtarget.h
index 07dc280d8288b9..d913f22bd5ba9d 100644
--- a/llvm/lib/Target/PowerPC/PPCSubtarget.h
+++ b/llvm/lib/Target/PowerPC/PPCSubtarget.h
@@ -245,30 +245,8 @@ class PPCSubtarget : public PPCGenSubtargetInfo {
   /// True if the GV will be accessed via an indirect symbol.
   bool isGVIndirectSymbol(const GlobalValue *GV) const;
 
-  bool tocDataChecks(unsigned PointerSize, const GlobalVariable *GV) const {
-    // TODO: These asserts should be updated as more support for the toc data
-    // transformation is added (struct support, etc.).
-    assert(
-        PointerSize >= GV->getAlign().valueOrOne().value() &&
-        "GlobalVariables with an alignment requirement stricter than TOC entry "
-        "size not supported by the toc data transformation.");
-
-    Type *GVType = GV->getValueType();
-    assert(GVType->isSized() && "A GlobalVariable's size must be known to be "
-                                "supported by the toc data transformation.");
-    if (GV->getParent()->getDataLayout().getTypeSizeInBits(GVType) >
-        PointerSize * 8)
-      report_fatal_error(
-          "A GlobalVariable with size larger than a TOC entry is not currently "
-          "supported by the toc data transformation.");
-    if (GV->hasLocalLinkage() || GV->hasPrivateLinkage())
-      report_fatal_error(
-          "A GlobalVariable with private or local linkage is not "
-          "currently supported by the toc data transformation.");
-    assert(!GV->hasCommonLinkage() &&
-           "Tentative definitions cannot have the mapping class XMC_TD.");
-    return true;
-  }
+  void tocDataChecks(unsigned PointerSize, const GlobalVariable *GV) const;
+
   /// True if the ABI is descriptor based.
   bool usesFunctionDescriptors() const {
     // Both 32-bit and 64-bit AIX are descriptor based. For ELF only the 64-bit

>From 881c5a3eefbcc990cfa486a5157c123f9da7c27c Mon Sep 17 00:00:00 2001
From: Zaara Syeda <syzaara at cpap8104.rtp.raleigh.ibm.com>
Date: Mon, 22 Jan 2024 11:35:49 -0500
Subject: [PATCH 7/9] Address review

---
 llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp b/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp
index 44c4134388ea5d..2462cbb1928235 100644
--- a/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp
+++ b/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp
@@ -510,8 +510,7 @@ SDNode *PPCDAGToDAGISel::getGlobalBaseReg() {
 }
 
 // Check if a SDValue has the toc-data attribute.
-static bool hasTocDataAttr(SDValue Val, unsigned PointerSize,
-                           const PPCSubtarget *Subtarget) {
+static bool hasTocDataAttr(SDValue Val, unsigned PointerSize) {
   GlobalAddressSDNode *GA = dyn_cast<GlobalAddressSDNode>(Val);
   if (!GA)
     return false;
@@ -6098,7 +6097,7 @@ void PPCDAGToDAGISel::Select(SDNode *N) {
       assert(isAIXABI && "ELF ABI already handled");
 
       if (hasTocDataAttr(N->getOperand(0),
-                         CurDAG->getDataLayout().getPointerSize(), Subtarget)) {
+                         CurDAG->getDataLayout().getPointerSize())) {
         replaceWith(PPC::ADDItoc, N, MVT::i32);
         return;
       }
@@ -6111,7 +6110,7 @@ void PPCDAGToDAGISel::Select(SDNode *N) {
       assert(isAIXABI && "ELF ABI handled in common SelectCode");
 
       if (hasTocDataAttr(N->getOperand(0),
-                         CurDAG->getDataLayout().getPointerSize(), Subtarget)) {
+                         CurDAG->getDataLayout().getPointerSize())) {
         replaceWith(PPC::ADDItoc8, N, MVT::i64);
         return;
       }

>From 0e248e276736644ecd9fb2ab6973097ce9efe1b8 Mon Sep 17 00:00:00 2001
From: Zaara Syeda <syzaara at cpap8104.rtp.raleigh.ibm.com>
Date: Tue, 30 Jan 2024 15:49:13 -0500
Subject: [PATCH 8/9] Address review

---
 clang/include/clang/Driver/Options.td | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 872cfae01f63b6..7d94bb2ea9fc35 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -3585,16 +3585,16 @@ defm tocdata : BoolOption<"m","tocdata",
   "This is the default. TOC data transformation is not applied to any"
   "variables. Only variables specified explicitly in -mtocdata= will"
   "have the TOC data transformation.">,
-  BothFlags<[], [ClangOption, CLOption]>>, Group<m_Group>;
+  BothFlags<[TargetSpecific], [ClangOption, CLOption]>>, Group<m_Group>;
 def mtocdata_EQ : CommaJoined<["-"], "mtocdata=">,
   Visibility<[ClangOption, CC1Option]>,
-  Flags<[TargetSpecific]>,
+  Flags<[TargetSpecific]>, Group<m_Group>,
   HelpText<"Specifies a list of variables to which the TOC data transformation"
            "will be applied.">,
   MarshallingInfoStringVector<CodeGenOpts<"TocDataVarsUserSpecified">>;
 def mno_tocdata_EQ : CommaJoined<["-"], "mno-tocdata=">,
   Visibility<[ClangOption, CC1Option]>,
-  Flags<[TargetSpecific]>,
+  Flags<[TargetSpecific]>, Group<m_Group>,
   HelpText<"Specifies a list of variables to be exempt from the TOC data"
            "transformation.">,
   MarshallingInfoStringVector<CodeGenOpts<"NoTocDataVars">>;

>From f54af62d5c3938618f7b84f054573476558ac44c Mon Sep 17 00:00:00 2001
From: Zaara Syeda <syzaara at cpap8104.rtp.raleigh.ibm.com>
Date: Mon, 19 Feb 2024 21:58:46 -0500
Subject: [PATCH 9/9] Address review

---
 clang/lib/CodeGen/Targets/PPC.cpp             | 17 ++++++++--------
 llvm/lib/MC/MCSectionXCOFF.cpp                |  2 +-
 llvm/lib/Target/PowerPC/PPCSubtarget.cpp      |  6 ++----
 .../CodeGen/PowerPC/toc-data-struct-array.ll  | 20 ++++++++-----------
 4 files changed, 19 insertions(+), 26 deletions(-)

diff --git a/clang/lib/CodeGen/Targets/PPC.cpp b/clang/lib/CodeGen/Targets/PPC.cpp
index 6d9c979b0142e8..00b04723f17dd2 100644
--- a/clang/lib/CodeGen/Targets/PPC.cpp
+++ b/clang/lib/CodeGen/Targets/PPC.cpp
@@ -302,26 +302,25 @@ void AIXTargetCodeGenInfo::setTargetAttributes(
         M.getDiags().Report(D->getLocation(), diag::warn_toc_unsupported_type)
             << GVId << Msg;
     };
-    if (!Ty || Ty->isIncompleteType()) {
+    if (!Ty || Ty->isIncompleteType())
       reportUnsupportedWarning(EmitDiagnostic, "of incomplete type");
-    } else if (RDecl && RDecl->hasFlexibleArrayMember()) {
+    else if (RDecl && RDecl->hasFlexibleArrayMember())
       reportUnsupportedWarning(EmitDiagnostic,
                                "it contains a flexible array member");
-    } else if (VarD->getTLSKind() != VarDecl::TLS_None) {
+    else if (VarD->getTLSKind() != VarDecl::TLS_None)
       reportUnsupportedWarning(EmitDiagnostic, "of thread local storage");
-    } else if (PointerSize < Context.getTypeInfo(VarD->getType()).Width / 8) {
+    else if (PointerSize < Context.getTypeInfo(VarD->getType()).Width / 8)
       reportUnsupportedWarning(EmitDiagnostic,
                                "variable is larger than a pointer");
-    } else if (PointerSize < Alignment) {
+    else if (PointerSize < Alignment)
       reportUnsupportedWarning(EmitDiagnostic,
                                "variable is aligned wider than a pointer");
-    } else if (D->hasAttr<SectionAttr>()) {
+    else if (D->hasAttr<SectionAttr>())
       reportUnsupportedWarning(EmitDiagnostic,
                                "variable has a section attribute");
-    } else if (GV->hasExternalLinkage() ||
-               (M.getCodeGenOpts().AllTocData && !GV->hasLocalLinkage())) {
+    else if (GV->hasExternalLinkage() ||
+             (M.getCodeGenOpts().AllTocData && !GV->hasLocalLinkage()))
       GVar->addAttribute("toc-data");
-    }
   }
 }
 
diff --git a/llvm/lib/MC/MCSectionXCOFF.cpp b/llvm/lib/MC/MCSectionXCOFF.cpp
index fcbf03ade221ef..609ef096293042 100644
--- a/llvm/lib/MC/MCSectionXCOFF.cpp
+++ b/llvm/lib/MC/MCSectionXCOFF.cpp
@@ -87,7 +87,7 @@ void MCSectionXCOFF::printSwitchToSection(const MCAsmInfo &MAI, const Triple &T,
     if (getKind().isCommon() && !getKind().isBSSLocal())
       return;
 
-    assert(getKind().isBSS() && "Unexepected section kind for toc-data");
+    assert(getKind().isBSS() && "Unexpected section kind for toc-data");
     printCsectDirective(OS);
     return;
   }
diff --git a/llvm/lib/Target/PowerPC/PPCSubtarget.cpp b/llvm/lib/Target/PowerPC/PPCSubtarget.cpp
index becbbe125bd9fd..a0d1c0074c804b 100644
--- a/llvm/lib/Target/PowerPC/PPCSubtarget.cpp
+++ b/llvm/lib/Target/PowerPC/PPCSubtarget.cpp
@@ -202,11 +202,9 @@ void PPCSubtarget::tocDataChecks(unsigned PointerSize,
     report_fatal_error(
         "A GlobalVariable with size larger than a TOC entry is not currently "
         "supported by the toc data transformation.");
-  if (GV->hasLocalLinkage() || GV->hasPrivateLinkage())
-    report_fatal_error("A GlobalVariable with private or local linkage is not "
+  if (GV->hasPrivateLinkage())
+    report_fatal_error("A GlobalVariable with private linkage is not "
                        "currently supported by the toc data transformation.");
-  assert(!GV->hasCommonLinkage() &&
-         "Tentative definitions cannot have the mapping class XMC_TD.");
 }
 
 bool PPCSubtarget::isGVIndirectSymbol(const GlobalValue *GV) const {
diff --git a/llvm/test/CodeGen/PowerPC/toc-data-struct-array.ll b/llvm/test/CodeGen/PowerPC/toc-data-struct-array.ll
index 5a1f1438e33d45..a5c9a8b909d1cf 100644
--- a/llvm/test/CodeGen/PowerPC/toc-data-struct-array.ll
+++ b/llvm/test/CodeGen/PowerPC/toc-data-struct-array.ll
@@ -34,15 +34,14 @@ attributes #1 = { noinline }
 ; CHECK-NEXT: .space    4
 
 ; OBJ32:  Symbol {
-; OBJ32:    Index: 9
-; OBJ32-NEXT:    Name: a
+; OBJ32:    Name: a
 ; OBJ32-NEXT:    Value (RelocatableAddress): 0x3C
 ; OBJ32-NEXT:    Section: .data
 ; OBJ32-NEXT:    Type: 0x0
 ; OBJ32-NEXT:    StorageClass: C_EXT (0x2)
 ; OBJ32-NEXT:    NumberOfAuxEntries: 1
 ; OBJ32-NEXT:    CSECT Auxiliary Entry {
-; OBJ32-NEXT:      Index: 10
+; OBJ32-NEXT:      Index: {{[0-9]+}}
 ; OBJ32-NEXT:      SectionLen: 2
 ; OBJ32-NEXT:      ParameterHashIndex: 0x0
 ; OBJ32-NEXT:      TypeChkSectNum: 0x0
@@ -54,15 +53,14 @@ attributes #1 = { noinline }
 ; OBJ32-NEXT:    }
 ; OBJ32-NEXT:  }
 ; OBJ32-NEXT:  Symbol {
-; OBJ32-NEXT:    Index: 11
-; OBJ32-NEXT:    Name: b
+; OBJ32:    Name: b
 ; OBJ32-NEXT:    Value (RelocatableAddress): 0x40
 ; OBJ32-NEXT:    Section: .data
 ; OBJ32-NEXT:    Type: 0x0
 ; OBJ32-NEXT:    StorageClass: C_EXT (0x2)
 ; OBJ32-NEXT:    NumberOfAuxEntries: 1
 ; OBJ32-NEXT:    CSECT Auxiliary Entry {
-; OBJ32-NEXT:      Index: 12
+; OBJ32-NEXT:      Index: {{[0-9]+}}
 ; OBJ32-NEXT:      SectionLen: 4
 ; OBJ32-NEXT:      ParameterHashIndex: 0x0
 ; OBJ32-NEXT:      TypeChkSectNum: 0x0
@@ -75,15 +73,14 @@ attributes #1 = { noinline }
 ; OBJ32-NEXT:  }
 
 ; OBJ64:  Symbol {
-; OBJ64:    Index: 9
-; OBJ64-NEXT:    Name: a
+; OBJ64:    Name: a
 ; OBJ64-NEXT:    Value (RelocatableAddress): 0x48
 ; OBJ64-NEXT:    Section: .data
 ; OBJ64-NEXT:    Type: 0x0
 ; OBJ64-NEXT:    StorageClass: C_EXT (0x2)
 ; OBJ64-NEXT:    NumberOfAuxEntries: 1
 ; OBJ64-NEXT:    CSECT Auxiliary Entry {
-; OBJ64-NEXT:      Index: 10
+; OBJ64-NEXT:      Index: {{[0-9]+}}
 ; OBJ64-NEXT:      SectionLen: 2
 ; OBJ64-NEXT:      ParameterHashIndex: 0x0
 ; OBJ64-NEXT:      TypeChkSectNum: 0x0
@@ -94,15 +91,14 @@ attributes #1 = { noinline }
 ; OBJ64-NEXT:    }
 ; OBJ64-NEXT:  }
 ; OBJ64-NEXT:  Symbol {
-; OBJ64-NEXT:    Index: 11
-; OBJ64-NEXT:    Name: b
+; OBJ64:    Name: b
 ; OBJ64-NEXT:    Value (RelocatableAddress): 0x4C
 ; OBJ64-NEXT:    Section: .data
 ; OBJ64-NEXT:    Type: 0x0
 ; OBJ64-NEXT:    StorageClass: C_EXT (0x2)
 ; OBJ64-NEXT:    NumberOfAuxEntries: 1
 ; OBJ64-NEXT:    CSECT Auxiliary Entry {
-; OBJ64-NEXT:      Index: 12
+; OBJ64-NEXT:      Index: {{[0-9]+}}
 ; OBJ64-NEXT:      SectionLen: 4
 ; OBJ64-NEXT:      ParameterHashIndex: 0x0
 ; OBJ64-NEXT:      TypeChkSectNum: 0x0



More information about the cfe-commits mailing list