[clang] [llvm] [AIX][TOC] Add -mtocdata/-mno-tocdata options on AIX (PR #67999)
Zaara Syeda via cfe-commits
cfe-commits at lists.llvm.org
Thu Jan 18 13:01:20 PST 2024
https://github.com/syzaara updated https://github.com/llvm/llvm-project/pull/67999
>From dced11bd242aba08158a5a0a399b2b0ea7381a69 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/6] [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 2e658557b0e310c..c6c8813d6124f7a 100644
--- a/clang/docs/UsersManual.rst
+++ b/clang/docs/UsersManual.rst
@@ -4028,7 +4028,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 b202d01af0ed6ce..fa0ed80f4cb3adc 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 676f1a62b49dd0d..b1c4c7658b29faf 100644
--- a/clang/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td
@@ -579,6 +579,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 715e0c0dc8fa84e..7269ad307eb9551 100644
--- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td
+++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -93,6 +93,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 9689f12fd01417b..197abb659e72528 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -3520,6 +3520,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 a5da0aa2965a000..f6e2ad200dab00f 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 41ff4a992f194ae..bb83311a48c5426 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -623,6 +623,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
@@ -649,6 +671,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 40dddde508c1772..3032a9c1ee3c09f 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 aed8734b2bab0ff..f0f050a874f7479 100644
--- a/clang/lib/Driver/ToolChains/AIX.cpp
+++ b/clang/lib/Driver/ToolChains/AIX.cpp
@@ -429,6 +429,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 {
@@ -436,6 +520,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 e5f8c0746a99dd4..644e3a0a24c0455 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 000000000000000..635ad53ce8c5d2d
--- /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 000000000000000..842fd05efa5c120
--- /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 000000000000000..cdf4b0cf0e05b08
--- /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 000000000000000..6f80ede29c7c79b
--- /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 000000000000000..1490b9353f1f055
--- /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 000000000000000..80d92ee1a90b4bc
--- /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 000000000000000..fe0d97ea02db1f5
--- /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 18bc4d108b156bf..720fec4904095fb 100644
--- a/llvm/include/llvm/ADT/STLExtras.h
+++ b/llvm/include/llvm/ADT/STLExtras.h
@@ -1940,6 +1940,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 02b1b972f339bf0..ac825a1001939e8 100644
--- a/llvm/lib/MC/MCSectionXCOFF.cpp
+++ b/llvm/lib/MC/MCSectionXCOFF.cpp
@@ -82,8 +82,7 @@ void MCSectionXCOFF::printSwitchToSection(const MCAsmInfo &MAI, const Triple &T,
}
if (isCsect() && getMappingClass() == XCOFF::XMC_TD) {
- 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 b57d185bb638b8c..9e3ed6f03b50512 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->hasLocalLinkage() || GV->hasPrivateLinkage())
report_fatal_error("A GlobalVariable with private or local 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 000000000000000..90f40d9f0fec951
--- /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 000000000000000..7443fe96f6f2d71
--- /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 1a6d00bc7688dd6961e3f2d09504b2427aa95ee7 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/6] 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 c6c8813d6124f7a..f657e05a1b2eddc 100644
--- a/clang/docs/UsersManual.rst
+++ b/clang/docs/UsersManual.rst
@@ -4046,6 +4046,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 7269ad307eb9551..582fab4ae6910ef 100644
--- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td
+++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -93,8 +93,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 197abb659e72528..0a7d86505de1f43 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -3520,25 +3520,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 bb83311a48c5426..f7886aebe87b6c0 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -632,9 +632,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 3032a9c1ee3c09f..00bd3bc8d661c50 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 f0f050a874f7479..f57305f45847e56 100644
--- a/clang/lib/Driver/ToolChains/AIX.cpp
+++ b/clang/lib/Driver/ToolChains/AIX.cpp
@@ -483,10 +483,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) {
@@ -505,10 +503,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 cdf4b0cf0e05b08..9d7c949c729b81b 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 f23461ad86202ae37947c5ad1099e301b23b3589 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/6] 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 | 35 ++------
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(+), 108 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 f657e05a1b2eddc..335e98e04a400d5 100644
--- a/clang/docs/UsersManual.rst
+++ b/clang/docs/UsersManual.rst
@@ -4057,6 +4057,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 f7886aebe87b6c0..a2433ffefa001dd 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -630,7 +630,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 00bd3bc8d661c50..44ad4dfeac6606d 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 f57305f45847e56..0d20aa0bf24436e 100644
--- a/clang/lib/Driver/ToolChains/AIX.cpp
+++ b/clang/lib/Driver/ToolChains/AIX.cpp
@@ -507,7 +507,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 635ad53ce8c5d2d..db23d74759eeff8 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 842fd05efa5c120..8183e3b727e7b36 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 6f80ede29c7c79b..a717995cdceb198 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 1490b9353f1f055..000000000000000
--- 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 4f15ba497d84c45..a7a52155e68e708 100644
--- a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
+++ b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
@@ -2520,7 +2520,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 9e3ed6f03b50512..dbc5b50d3d84d04 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,33 +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->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;
+ return Subtarget->tocDataChecks(PointerSize, GV);
}
/// isInt32Immediate - This method tests to see if the node is a 32-bit constant
@@ -6114,7 +6089,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;
}
@@ -6127,7 +6102,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 306a52dca8362bb..07dc280d8288b97 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 000000000000000..f870e996a401924
--- /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 7443fe96f6f2d71..5a1f1438e33d455 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 18bd32a4428a875942a8bd8839769acc8e8eb016 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/6] 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 335e98e04a400d5..b77ad70cb51d1d7 100644
--- a/clang/docs/UsersManual.rst
+++ b/clang/docs/UsersManual.rst
@@ -4061,7 +4061,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 fa0ed80f4cb3adc..acb405a59472740 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 b92c8af62ff5f957dd73d7a2e2c5f503ac9ff39d 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/6] 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 b77ad70cb51d1d7..fad4fb7270478be 100644
--- a/clang/docs/UsersManual.rst
+++ b/clang/docs/UsersManual.rst
@@ -4061,7 +4061,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 ff356b5454ea68c97e038cd4144bc3808d3afbf7 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/6] 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 44ad4dfeac6606d..6d9c979b0142e8e 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 0d20aa0bf24436e..c1b3ba3958e405e 100644
--- a/clang/lib/Driver/ToolChains/AIX.cpp
+++ b/clang/lib/Driver/ToolChains/AIX.cpp
@@ -439,12 +439,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 9d7c949c729b81b..ba8955530e46700 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 a7a52155e68e708..b0a5af604d83c4f 100644
--- a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
+++ b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
@@ -2521,8 +2521,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 dbc5b50d3d84d04..12c310af28991c2 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 c9740818c9bfd6f..72fb02f0eb1f038 100644
--- a/llvm/lib/Target/PowerPC/PPCSubtarget.cpp
+++ b/llvm/lib/Target/PowerPC/PPCSubtarget.cpp
@@ -172,6 +172,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 07dc280d8288b97..d913f22bd5ba9d1 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
More information about the cfe-commits
mailing list