Index: clang/docs/UsersManual.rst =================================================================== --- clang/docs/UsersManual.rst +++ clang/docs/UsersManual.rst @@ -3153,6 +3153,45 @@ .. _c: +Mark TOC / No TOC Data (AIX-specific) +------------------------------------------- + +When -mtocdata is specified, all external linkage variables and variables with +static storage duration, including static data members of classes and +block-scope static variables will be marked with the toc-data attribute. +Alternatively, the user can specify a comma separated list of external linkage +variables using -mtocdata= using the mangled names. + +The toc-data attribute results in the variable being place directly in the TOC, +rather than having the address of the variable being placed in the TOC. This +results in having one less load when loading the data from the TOC. +The effects of the toc-data attribute only take effect on AIX when the symbol +is independently-generated (e.g. not placed in a pool). + +The default is -mno-tocdata and a user can then use -mtocdata= to add +which variables will be an exception to -mno-tocdata. Alternatively, a user +may specify -mtocdata to mark all suitable variables with toc-data and specify +-mno-tocdata= to add which variables will be an exception to -mtocdata. + +.. option:: -mtocdata + + Mark all external linkage variables and variables with static storage duration + that are not explicitly specified with -mno-tocdata= as toc-data. + +.. option:: -mno-tocdata + + This is the default behaviour. + Only variables explicitly specified with -mtocdata= will be treated as toc-data. + +.. option:: -mtocdata= + + Mark the specified external linkage variables as "toc-data" if valid, or emit + diagnostics otherwise. + +.. option:: -mno-tocdata= + + Mark the specified external linkage variables are exceptions to toc-data. + C Language Features =================== Index: clang/include/clang/Basic/CodeGenOptions.h =================================================================== --- clang/include/clang/Basic/CodeGenOptions.h +++ clang/include/clang/Basic/CodeGenOptions.h @@ -403,6 +403,15 @@ /// List of dynamic shared object files to be loaded as pass plugins. std::vector PassPlugins; + /// List of global variables explicitly specified by the user as toc-data. + std::vector TocDataVarsUserSpecified; + + /// List of global variables that over-ride the toc-data default. + std::vector 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 /// by sanitizer coverage pass. Index: clang/include/clang/Basic/DiagnosticDriverKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticDriverKinds.td +++ clang/include/clang/Basic/DiagnosticDriverKinds.td @@ -554,6 +554,11 @@ "ignoring '-mgpopt' option as it cannot be used with %select{|the implicit" " usage of }0-mabicalls">, InGroup; +def warn_drv_unsupported_tocdata: Warning< + "ignoring '-mtocdata' as it is only supported for -mcmodel=small">, + InGroup; +def warn_toc_unsupported_type : Warning<"The -m[no-]tocdata option is ignored " + "for %0 because %1.">, InGroup; def warn_drv_unsupported_sdata : Warning< "ignoring '-msmall-data-limit=' with -mcmodel=large for -fpic or RV64">, InGroup; Index: clang/include/clang/Driver/Options.td =================================================================== --- clang/include/clang/Driver/Options.td +++ clang/include/clang/Driver/Options.td @@ -3401,6 +3401,26 @@ MetaVarName<"">, HelpText<"Load pass plugin from a dynamic shared object file (only with new pass manager).">, MarshallingInfoStringVector>; +def mtocdata : Flag<["-"], "mtocdata">, + Visibility<[ClangOption, CLOption, DXCOption, CC1Option]>, + Flags<[TargetSpecific]>, + HelpText<"All suitable variables will be treated as toc-data">, + MarshallingInfoFlag>; +def mno_tocdata : Flag<["-"], "mno-tocdata">, + Visibility<[ClangOption, CLOption, DXCOption, CC1Option]>, + Flags<[TargetSpecific]>, + HelpText<"This is the default. Variables are treated as not having toc-data attribute." + "Only variables specified explicitly in -mtocdata=<> will be treated as toc-data">; +def mtocdata_EQ : CommaJoined<["-"], "mtocdata=">, + Visibility<[ClangOption, CLOption, DXCOption, CC1Option]>, + Flags<[TargetSpecific]>, + HelpText<"Specifies a list of variables to treat as having toc-data attribute">, + MarshallingInfoStringVector>; +def mno_tocdata_EQ : CommaJoined<["-"], "mno-tocdata=">, + Visibility<[ClangOption, CLOption, DXCOption, CC1Option]>, + Flags<[TargetSpecific]>, + HelpText<"Specifies a list of variables to be exempt from having the toc-data attribute">, + MarshallingInfoStringVector>; defm preserve_as_comments : BoolFOption<"preserve-as-comments", CodeGenOpts<"PreserveAsmComments">, DefaultTrue, NegFlag(&D), GV, *this); // Make sure the result is of the correct type. LangAS ExpectedAS = Ty.getAddressSpace(); Index: clang/lib/CodeGen/Targets/PPC.cpp =================================================================== --- clang/lib/CodeGen/Targets/PPC.cpp +++ clang/lib/CodeGen/Targets/PPC.cpp @@ -8,6 +8,7 @@ #include "ABIInfoImpl.h" #include "TargetInfo.h" +#include "clang/Driver/DriverDiagnostic.h" using namespace clang; using namespace clang::CodeGen; @@ -145,6 +146,9 @@ 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 @@ 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(GV)) { + auto GVId = M.getMangledName(dyn_cast(D)); + + // Is this a global variable specified by the user as toc-data? + bool UserSpecifiedTOC = + llvm::binary_search(M.getCodeGenOpts().TocDataVarsUserSpecified, GVId); + bool UserSpecifiedNoTOC = + llvm::binary_search(M.getCodeGenOpts().NoTocDataVars, GVId); + + if (UserSpecifiedTOC || + (M.getCodeGenOpts().AllTocData && + (!UserSpecifiedNoTOC || !GV->hasExternalLinkage()))) { + const unsigned long PointerSize = + GV->getParent()->getDataLayout().getPointerSizeInBits() / 8; + ASTContext &Context = D->getASTContext(); + auto *VarD = dyn_cast(D); + assert(VarD && "Invalid declaration of global variable."); + + unsigned Alignment = Context.toBits(Context.getDeclAlign(D)) / 8; + const auto *Ty = VarD->getType().getTypePtr(); + + if (!Ty || Ty->isIncompleteType()) { + if (UserSpecifiedTOC) + M.getDiags().Report(D->getLocation(), diag::warn_toc_unsupported_type) + << GVId << "of incomplete type"; + } else if (VarD->getTLSKind() != VarDecl::TLS_None) { + if (UserSpecifiedTOC) + 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 (UserSpecifiedTOC) + M.getDiags().Report(D->getLocation(), diag::warn_toc_unsupported_type) + << GVId << "variable is larger than a pointer"; + } else if (PointerSize < Alignment) { + if (UserSpecifiedTOC) + M.getDiags().Report(D->getLocation(), diag::warn_toc_unsupported_type) + << GVId << "variable is aligned wider than a pointer"; + } else if (D->hasAttr()) { + if (UserSpecifiedTOC) + M.getDiags().Report(D->getLocation(), diag::warn_toc_unsupported_type) + << GVId << "of a section attribute"; + } else if (UserSpecifiedTOC && !GV->hasExternalLinkage()) { + M.getDiags().Report(D->getLocation(), diag::warn_toc_unsupported_type) + << GVId << "variable does not have external linkage"; + } else { + if (UserSpecifiedNoTOC && !GV->hasExternalLinkage()) + M.getDiags().Report(D->getLocation(), diag::warn_toc_unsupported_type) + << GVId << "variable does not have external linkage"; + + GVar->addAttribute("toc-data"); + } + } + } +} + // PowerPC-32 namespace { /// PPC32_SVR4_ABIInfo - The 32-bit PowerPC ELF (SVR4) ABI information. Index: clang/lib/Driver/ToolChains/AIX.cpp =================================================================== --- clang/lib/Driver/ToolChains/AIX.cpp +++ clang/lib/Driver/ToolChains/AIX.cpp @@ -415,6 +415,89 @@ llvm_unreachable("Unexpected C++ library type; only libc++ is supported."); } +// This function processes all the mtocdata options to build the final +// simplified tocdata 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 { @@ -422,6 +505,11 @@ 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"); Index: clang/lib/Frontend/CompilerInstance.cpp =================================================================== --- clang/lib/Frontend/CompilerInstance.cpp +++ clang/lib/Frontend/CompilerInstance.cpp @@ -1044,6 +1044,11 @@ 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. Index: clang/test/CodeGen/PowerPC/toc-data-attribute.c =================================================================== --- /dev/null +++ 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" } Index: clang/test/CodeGen/PowerPC/toc-data-attribute.cpp =================================================================== --- /dev/null +++ clang/test/CodeGen/PowerPC/toc-data-attribute.cpp @@ -0,0 +1,73 @@ +// RUN: %clang_cc1 %s -triple powerpc-ibm-aix-xcoff -S -mtocdata -emit-llvm -o - 2>&1 | FileCheck %s -check-prefixes=CHECK32 +// RUN: %clang_cc1 %s -triple powerpc-ibm-aix-xcoff -S -mtocdata=_ZL1s,_ZZ4testvE7counter,_ZN11MyNamespace10myVariableE -emit-llvm -o - 2>&1 | FileCheck %s -check-prefixes=CHECK32WARN +// RUN: %clang_cc1 %s -triple powerpc-ibm-aix-xcoff -S -mtocdata -mno-tocdata=_ZL1s,_ZZ4testvE7counter,_ZN11MyNamespace10myVariableE -emit-llvm -o - 2>&1 | FileCheck %s -check-prefixes=CHECK32WARNNOTOC +// RUN: %clang_cc1 %s -triple powerpc64-ibm-aix-xcoff -S -mtocdata -emit-llvm -o - 2>&1 | FileCheck %s -check-prefixes=CHECK64 +// RUN: %clang_cc1 %s -triple powerpc64-ibm-aix-xcoff -S -mtocdata=_ZL1s,_ZZ4testvE7counter,_ZN11MyNamespace10myVariableE -emit-llvm -o - 2>&1 | FileCheck %s -check-prefixes=CHECK64WARN +// RUN: %clang_cc1 %s -triple powerpc64-ibm-aix-xcoff -S -mtocdata -mno-tocdata=_ZL1s,_ZZ4testvE7counter,_ZN11MyNamespace10myVariableE -emit-llvm -o - 2>&1 | FileCheck %s -check-prefixes=CHECK64WARNNOTOC + +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; +} + +// CHECK32: @_ZN11MyNamespace10myVariableE = global i32 10, align 4 #0 +// CHECK32: @_ZL1s = internal global i32 100, align 4 #0 +// CHECK32: @_ZZ4testvE7counter = linkonce_odr global i32 0, align 4 #0 +// CHECK32: attributes #0 = { "toc-data" } + +// CHECK32WARN: The -m[no-]tocdata option is ignored for _ZZ4testvE7counter because variable does not have external linkage +// CHECK32WARN: The -m[no-]tocdata option is ignored for _ZL1s because variable does not have external linkage +// CHECK32WARN: @_ZN11MyNamespace10myVariableE = global i32 10, align 4 #0 +// CHECK32WARN-NOT: @_ZL1s = internal global i32 100, align 4 #0 +// CHECK32WARN-NOT: @_ZZ4testvE7counter = linkonce_odr global i32 0, align 4 #0 +// CHECK32WARN: attributes #0 = { "toc-data" } + +// CHECK32WARNNOTOC: The -m[no-]tocdata option is ignored for _ZZ4testvE7counter because variable does not have external linkage +// CHECK32WARNNOTOC: The -m[no-]tocdata option is ignored for _ZL1s because variable does not have external linkage +// CHECK32WARNNOTOC-NOT: @_ZN11MyNamespace10myVariableE = global i32 10, align 4 #0 +// CHECK32WARNNOTOC: @_ZL1s = internal global i32 100, align 4 #0 +// CHECK32WARNNOTOC: @_ZZ4testvE7counter = linkonce_odr global i32 0, align 4 #0 +// CHECK32WARNNOTOC: attributes #0 = { "toc-data" } + + +// CHECK64: @_ZN11MyNamespace10myVariableE = global i32 10, align 4 #0 +// CHECK64: @_ZL1s = internal global i32 100, align 4 #0 +// CHECK64: @_ZZ4testvE7counter = linkonce_odr global i32 0, align 4 #0 +// CHECK64: attributes #0 = { "toc-data" } + +// CHECK64WARN: The -m[no-]tocdata option is ignored for _ZZ4testvE7counter because variable does not have external linkage +// CHECK64WARN: The -m[no-]tocdata option is ignored for _ZL1s because variable does not have external linkage +// CHECK64WARN: @_ZN11MyNamespace10myVariableE = global i32 10, align 4 #0 +// CHECK64WARN-NOT: @_ZL1s = internal global i32 100, align 4 #0 +// CHECK64WARN-NOT: @_ZZ4testvE7counter = linkonce_odr global i32 0, align 4 #0 +// CHECK64WARN: attributes #0 = { "toc-data" } + +// CHECK64WARNNOTOC: The -m[no-]tocdata option is ignored for _ZZ4testvE7counter because variable does not have external linkage +// CHECK64WARNNOTOC: The -m[no-]tocdata option is ignored for _ZL1s because variable does not have external linkage +// CHECK64WARNNOTOC-NOT: @_ZN11MyNamespace10myVariableE = global i32 10, align 4 #0 +// CHECK64WARNNOTOC: @_ZL1s = internal global i32 100, align 4 #0 +// CHECK64WARNNOTOC: @_ZZ4testvE7counter = linkonce_odr global i32 0, align 4 #0 +// CHECK64WARNNOTOC: attributes #0 = { "toc-data" } Index: clang/test/CodeGen/PowerPC/toc-data-diagnostics.c =================================================================== --- /dev/null +++ clang/test/CodeGen/PowerPC/toc-data-diagnostics.c @@ -0,0 +1,41 @@ +// RUN: %clang_cc1 %s -triple=powerpc-ibm-aix-xcoff -S -mtocdata=h,g,f,e,d,c,b,a -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 -m[no-]tocdata option is ignored for a because variable is larger than a pointer.}} +long long b = 5; // expected-warning {{The -m[no-]tocdata option is ignored for b because variable is larger than a pointer.}} +int __attribute__((aligned(128))) c = 0; // expected-warning {{The -m[no-]tocdata option is ignored for c because variable is aligned wider than a pointer.}} +double d = 2.5; // expected-warning {{The -m[no-]tocdata option is ignored for d because variable is larger than a pointer.}} +int e __attribute__((section("foo"))) = 10; // expected-warning {{The -m[no-]tocdata option is ignored for e because of a section attribute.}} +__thread int f; // expected-warning {{The -m[no-]tocdata option is ignored for f because of thread local storage model.}} + +struct SomeStruct; +extern struct SomeStruct g; // expected-warning {{The -m[no-]tocdata option is ignored for g because of incomplete type.}} + +extern int h[]; // expected-warning {{The -m[no-]tocdata option is ignored for h because of incomplete type.}} + +int func() { + return a.x+b+c+d+e+f+h[0]; +} + +struct SomeStruct* getAddress(void) { + return &g; +} + +// 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: @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-NOT: attributes {{.*}} = { "toc-data" } Index: clang/test/CodeGen/PowerPC/toc-data-structs-arrays.cpp =================================================================== --- /dev/null +++ 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" } Index: clang/test/CodeGen/toc-data.c =================================================================== --- /dev/null +++ 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" } Index: clang/test/Driver/toc-conf.c =================================================================== --- /dev/null +++ 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" Index: clang/test/Driver/tocdata-cc1.c =================================================================== --- /dev/null +++ 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 Index: llvm/include/llvm/ADT/STLExtras.h =================================================================== --- llvm/include/llvm/ADT/STLExtras.h +++ llvm/include/llvm/ADT/STLExtras.h @@ -1951,6 +1951,19 @@ 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 auto binary_search(R &&Range, T &&Value) { + return std::binary_search(adl_begin(Range), adl_end(Range), + std::forward(Value)); +} + +template +auto binary_search(R &&Range, T &&Value, Compare C) { + return std::binary_search(adl_begin(Range), adl_end(Range), + std::forward(Value), C); +} + /// Provide wrappers to std::lower_bound which take ranges instead of having to /// pass begin/end explicitly. template auto lower_bound(R &&Range, T &&Value) { Index: llvm/lib/MC/MCSectionXCOFF.cpp =================================================================== --- llvm/lib/MC/MCSectionXCOFF.cpp +++ llvm/lib/MC/MCSectionXCOFF.cpp @@ -82,8 +82,7 @@ } 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; } Index: llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp =================================================================== --- llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp +++ llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp @@ -533,21 +533,11 @@ 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 " Index: llvm/test/CodeGen/PowerPC/toc-data-large-array.ll =================================================================== --- /dev/null +++ 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 + +@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. Index: llvm/test/CodeGen/PowerPC/toc-data-struct-array.ll =================================================================== --- /dev/null +++ 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 } + +@a = global %struct.small_struct zeroinitializer, align 2 #0 +@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