Skip to content

Commit 37b5eb0

Browse files
authored
[AIX][TOC] Add -mtocdata/-mno-tocdata options on AIX (#67999)
This patch enables support that the XL compiler had for AIX under -qdatalocal/-qdataimported.
1 parent e77324d commit 37b5eb0

25 files changed

+716
-36
lines changed

clang/docs/UsersManual.rst

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4227,7 +4227,68 @@ Clang expects the GCC executable "gcc.exe" compiled for
42274227

42284228
AIX
42294229
^^^
4230+
TOC Data Transformation
4231+
"""""""""""""""""""""""
4232+
TOC data transformation is off by default (``-mno-tocdata``).
4233+
When ``-mtocdata`` is specified, the TOC data transformation will be applied to
4234+
all suitable variables with static storage duration, including static data
4235+
members of classes and block-scope static variables (if not marked as exceptions,
4236+
see further below).
42304237

4238+
Suitable variables must:
4239+
4240+
- have complete types
4241+
- be independently generated (i.e., not placed in a pool)
4242+
- be at most as large as a pointer
4243+
- not be aligned more strictly than a pointer
4244+
- not be structs containing flexible array members
4245+
- not have internal linkage
4246+
- not have aliases
4247+
- not have section attributes
4248+
- not be thread local storage
4249+
4250+
The TOC data transformation results in the variable, not its address,
4251+
being placed in the TOC. This eliminates the need to load the address of the
4252+
variable from the TOC.
4253+
4254+
Note:
4255+
If the TOC data transformation is applied to a variable whose definition
4256+
is imported, the linker will generate fixup code for reading or writing to the
4257+
variable.
4258+
4259+
When multiple toc-data options are used, the last option used has the affect.
4260+
For example: -mno-tocdata=g5,g1 -mtocdata=g1,g2 -mno-tocdata=g2 -mtocdata=g3,g4
4261+
results in -mtocdata=g1,g3,g4
4262+
4263+
Names of variables not having external linkage will be ignored.
4264+
4265+
**Options:**
4266+
4267+
.. option:: -mno-tocdata
4268+
4269+
This is the default behaviour. Only variables explicitly specified with
4270+
``-mtocdata=`` will have the TOC data transformation applied.
4271+
4272+
.. option:: -mtocdata
4273+
4274+
Apply the TOC data transformation to all suitable variables with static
4275+
storage duration (including static data members of classes and block-scope
4276+
static variables) that are not explicitly specified with ``-mno-tocdata=``.
4277+
4278+
.. option:: -mno-tocdata=
4279+
4280+
Can be used in conjunction with ``-mtocdata`` to mark the comma-separated
4281+
list of external linkage variables, specified using their mangled names, as
4282+
exceptions to ``-mtocdata``.
4283+
4284+
.. option:: -mtocdata=
4285+
4286+
Apply the TOC data transformation to the comma-separated list of external
4287+
linkage variables, specified using their mangled names, if they are suitable.
4288+
Emit diagnostics for all unsuitable variables specified.
4289+
4290+
Default Visibility Export Mapping
4291+
"""""""""""""""""""""""""""""""""
42314292
The ``-mdefault-visibility-export-mapping=`` option can be used to control
42324293
mapping of default visibility to an explicit shared object export
42334294
(i.e. XCOFF exported visibility). Three values are provided for the option:

clang/include/clang/Basic/CodeGenOptions.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,15 @@ class CodeGenOptions : public CodeGenOptionsBase {
404404
/// List of pass builder callbacks.
405405
std::vector<std::function<void(llvm::PassBuilder &)>> PassBuilderCallbacks;
406406

407+
/// List of global variables explicitly specified by the user as toc-data.
408+
std::vector<std::string> TocDataVarsUserSpecified;
409+
410+
/// List of global variables that over-ride the toc-data default.
411+
std::vector<std::string> NoTocDataVars;
412+
413+
/// Flag for all global variables to be treated as toc-data.
414+
bool AllTocData;
415+
407416
/// Path to allowlist file specifying which objects
408417
/// (files, functions) should exclusively be instrumented
409418
/// by sanitizer coverage pass.

clang/include/clang/Basic/DiagnosticDriverKinds.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -587,6 +587,9 @@ def warn_drv_unsupported_gpopt : Warning<
587587
"ignoring '-mgpopt' option as it cannot be used with %select{|the implicit"
588588
" usage of }0-mabicalls">,
589589
InGroup<UnsupportedGPOpt>;
590+
def warn_drv_unsupported_tocdata: Warning<
591+
"ignoring '-mtocdata' as it is only supported for -mcmodel=small">,
592+
InGroup<OptionIgnored>;
590593
def warn_drv_unsupported_sdata : Warning<
591594
"ignoring '-msmall-data-limit=' with -mcmodel=large for -fpic or RV64">,
592595
InGroup<OptionIgnored>;

clang/include/clang/Basic/DiagnosticFrontendKinds.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,8 @@ def err_fe_backend_error_attr :
9494
def warn_fe_backend_warning_attr :
9595
Warning<"call to '%0' declared with 'warning' attribute: %1">, BackendInfo,
9696
InGroup<BackendWarningAttributes>;
97+
def warn_toc_unsupported_type : Warning<"-mtocdata option is ignored "
98+
"for %0 because %1">, InGroup<BackendWarningAttributes>;
9799

98100
def err_fe_invalid_code_complete_file : Error<
99101
"cannot locate code-completion file %0">, DefaultFatal;

clang/include/clang/Driver/Options.td

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3609,6 +3609,27 @@ def fpass_plugin_EQ : Joined<["-"], "fpass-plugin=">,
36093609
MetaVarName<"<dsopath>">,
36103610
HelpText<"Load pass plugin from a dynamic shared object file (only with new pass manager).">,
36113611
MarshallingInfoStringVector<CodeGenOpts<"PassPlugins">>;
3612+
defm tocdata : BoolOption<"m","tocdata",
3613+
CodeGenOpts<"AllTocData">, DefaultFalse,
3614+
PosFlag<SetTrue, [], [ClangOption, CC1Option],
3615+
"All suitable variables will have the TOC data transformation applied">,
3616+
NegFlag<SetFalse, [], [ClangOption, CC1Option],
3617+
"This is the default. TOC data transformation is not applied to any"
3618+
"variables. Only variables specified explicitly in -mtocdata= will"
3619+
"have the TOC data transformation.">,
3620+
BothFlags<[TargetSpecific], [ClangOption, CLOption]>>, Group<m_Group>;
3621+
def mtocdata_EQ : CommaJoined<["-"], "mtocdata=">,
3622+
Visibility<[ClangOption, CC1Option]>,
3623+
Flags<[TargetSpecific]>, Group<m_Group>,
3624+
HelpText<"Specifies a list of variables to which the TOC data transformation"
3625+
"will be applied.">,
3626+
MarshallingInfoStringVector<CodeGenOpts<"TocDataVarsUserSpecified">>;
3627+
def mno_tocdata_EQ : CommaJoined<["-"], "mno-tocdata=">,
3628+
Visibility<[ClangOption, CC1Option]>,
3629+
Flags<[TargetSpecific]>, Group<m_Group>,
3630+
HelpText<"Specifies a list of variables to be exempt from the TOC data"
3631+
"transformation.">,
3632+
MarshallingInfoStringVector<CodeGenOpts<"NoTocDataVars">>;
36123633
defm preserve_as_comments : BoolFOption<"preserve-as-comments",
36133634
CodeGenOpts<"PreserveAsmComments">, DefaultTrue,
36143635
NegFlag<SetFalse, [], [ClangOption, CC1Option],

clang/lib/CodeGen/CGDecl.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,7 @@ llvm::Constant *CodeGenModule::getOrCreateStaticVarDecl(
284284
setTLSMode(GV, D);
285285

286286
setGVProperties(GV, &D);
287+
getTargetCodeGenInfo().setTargetAttributes(cast<Decl>(&D), GV, *this);
287288

288289
// Make sure the result is of the correct type.
289290
LangAS ExpectedAS = Ty.getAddressSpace();

clang/lib/CodeGen/CodeGenModule.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -626,6 +626,26 @@ static bool checkAliasedGlobal(
626626
return true;
627627
}
628628

629+
// Emit a warning if toc-data attribute is requested for global variables that
630+
// have aliases and remove the toc-data attribute.
631+
static void checkAliasForTocData(llvm::GlobalVariable *GVar,
632+
const CodeGenOptions &CodeGenOpts,
633+
DiagnosticsEngine &Diags,
634+
SourceLocation Location) {
635+
if (GVar->hasAttribute("toc-data")) {
636+
auto GVId = GVar->getName();
637+
// Is this a global variable specified by the user as local?
638+
if ((llvm::binary_search(CodeGenOpts.TocDataVarsUserSpecified, GVId))) {
639+
Diags.Report(Location, diag::warn_toc_unsupported_type)
640+
<< GVId << "the variable has an alias";
641+
}
642+
llvm::AttributeSet CurrAttributes = GVar->getAttributes();
643+
llvm::AttributeSet NewAttributes =
644+
CurrAttributes.removeAttribute(GVar->getContext(), "toc-data");
645+
GVar->setAttributes(NewAttributes);
646+
}
647+
}
648+
629649
void CodeGenModule::checkAliases() {
630650
// Check if the constructed aliases are well formed. It is really unfortunate
631651
// that we have to do this in CodeGen, but we only construct mangled names
@@ -652,6 +672,12 @@ void CodeGenModule::checkAliases() {
652672
continue;
653673
}
654674

675+
if (getContext().getTargetInfo().getTriple().isOSAIX())
676+
if (const llvm::GlobalVariable *GVar =
677+
dyn_cast<const llvm::GlobalVariable>(GV))
678+
checkAliasForTocData(const_cast<llvm::GlobalVariable *>(GVar),
679+
getCodeGenOpts(), Diags, Location);
680+
655681
llvm::Constant *Aliasee =
656682
IsIFunc ? cast<llvm::GlobalIFunc>(Alias)->getResolver()
657683
: cast<llvm::GlobalAlias>(Alias)->getAliasee();

clang/lib/CodeGen/Targets/PPC.cpp

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include "ABIInfoImpl.h"
1010
#include "TargetInfo.h"
11+
#include "clang/Basic/DiagnosticFrontend.h"
1112

1213
using namespace clang;
1314
using namespace clang::CodeGen;
@@ -145,6 +146,9 @@ class AIXTargetCodeGenInfo : public TargetCodeGenInfo {
145146

146147
bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
147148
llvm::Value *Address) const override;
149+
150+
void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
151+
CodeGen::CodeGenModule &M) const override;
148152
};
149153
} // namespace
150154

@@ -265,6 +269,61 @@ bool AIXTargetCodeGenInfo::initDwarfEHRegSizeTable(
265269
return PPC_initDwarfEHRegSizeTable(CGF, Address, Is64Bit, /*IsAIX*/ true);
266270
}
267271

272+
void AIXTargetCodeGenInfo::setTargetAttributes(
273+
const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &M) const {
274+
if (!isa<llvm::GlobalVariable>(GV))
275+
return;
276+
277+
auto *GVar = dyn_cast<llvm::GlobalVariable>(GV);
278+
auto GVId = GV->getName();
279+
280+
// Is this a global variable specified by the user as toc-data?
281+
bool UserSpecifiedTOC =
282+
llvm::binary_search(M.getCodeGenOpts().TocDataVarsUserSpecified, GVId);
283+
// Assumes the same variable cannot be in both TocVarsUserSpecified and
284+
// NoTocVars.
285+
if (UserSpecifiedTOC ||
286+
((M.getCodeGenOpts().AllTocData) &&
287+
!llvm::binary_search(M.getCodeGenOpts().NoTocDataVars, GVId))) {
288+
const unsigned long PointerSize =
289+
GV->getParent()->getDataLayout().getPointerSizeInBits() / 8;
290+
auto *VarD = dyn_cast<VarDecl>(D);
291+
assert(VarD && "Invalid declaration of global variable.");
292+
293+
ASTContext &Context = D->getASTContext();
294+
unsigned Alignment = Context.toBits(Context.getDeclAlign(D)) / 8;
295+
const auto *Ty = VarD->getType().getTypePtr();
296+
const RecordDecl *RDecl =
297+
Ty->isRecordType() ? Ty->getAs<RecordType>()->getDecl() : nullptr;
298+
299+
bool EmitDiagnostic = UserSpecifiedTOC && GV->hasExternalLinkage();
300+
auto reportUnsupportedWarning = [&](bool ShouldEmitWarning, StringRef Msg) {
301+
if (ShouldEmitWarning)
302+
M.getDiags().Report(D->getLocation(), diag::warn_toc_unsupported_type)
303+
<< GVId << Msg;
304+
};
305+
if (!Ty || Ty->isIncompleteType())
306+
reportUnsupportedWarning(EmitDiagnostic, "of incomplete type");
307+
else if (RDecl && RDecl->hasFlexibleArrayMember())
308+
reportUnsupportedWarning(EmitDiagnostic,
309+
"it contains a flexible array member");
310+
else if (VarD->getTLSKind() != VarDecl::TLS_None)
311+
reportUnsupportedWarning(EmitDiagnostic, "of thread local storage");
312+
else if (PointerSize < Context.getTypeInfo(VarD->getType()).Width / 8)
313+
reportUnsupportedWarning(EmitDiagnostic,
314+
"variable is larger than a pointer");
315+
else if (PointerSize < Alignment)
316+
reportUnsupportedWarning(EmitDiagnostic,
317+
"variable is aligned wider than a pointer");
318+
else if (D->hasAttr<SectionAttr>())
319+
reportUnsupportedWarning(EmitDiagnostic,
320+
"variable has a section attribute");
321+
else if (GV->hasExternalLinkage() ||
322+
(M.getCodeGenOpts().AllTocData && !GV->hasLocalLinkage()))
323+
GVar->addAttribute("toc-data");
324+
}
325+
}
326+
268327
// PowerPC-32
269328
namespace {
270329
/// PPC32_SVR4_ABIInfo - The 32-bit PowerPC ELF (SVR4) ABI information.

clang/lib/Driver/ToolChains/AIX.cpp

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -433,13 +433,100 @@ void AIX::AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
433433
llvm_unreachable("Unexpected C++ library type; only libc++ is supported.");
434434
}
435435

436+
// This function processes all the mtocdata options to build the final
437+
// simplified toc data options to pass to CC1.
438+
static void addTocDataOptions(const llvm::opt::ArgList &Args,
439+
llvm::opt::ArgStringList &CC1Args,
440+
const Driver &D) {
441+
442+
// Check the global toc-data setting. The default is -mno-tocdata.
443+
// To enable toc-data globally, -mtocdata must be specified.
444+
// Additionally, it must be last to take effect.
445+
const bool TOCDataGloballyinEffect = [&Args]() {
446+
if (const Arg *LastArg =
447+
Args.getLastArg(options::OPT_mtocdata, options::OPT_mno_tocdata))
448+
return LastArg->getOption().matches(options::OPT_mtocdata);
449+
else
450+
return false;
451+
}();
452+
453+
// Currently only supported for small code model.
454+
if (TOCDataGloballyinEffect &&
455+
(Args.getLastArgValue(options::OPT_mcmodel_EQ).equals("large") ||
456+
Args.getLastArgValue(options::OPT_mcmodel_EQ).equals("medium"))) {
457+
D.Diag(clang::diag::warn_drv_unsupported_tocdata);
458+
return;
459+
}
460+
461+
enum TOCDataSetting {
462+
AddressInTOC = 0, // Address of the symbol stored in the TOC.
463+
DataInTOC = 1 // Symbol defined in the TOC.
464+
};
465+
466+
const TOCDataSetting DefaultTocDataSetting =
467+
TOCDataGloballyinEffect ? DataInTOC : AddressInTOC;
468+
469+
// Process the list of variables in the explicitly specified options
470+
// -mtocdata= and -mno-tocdata= to see which variables are opposite to
471+
// the global setting of tocdata in TOCDataGloballyinEffect.
472+
// Those that have the opposite setting to TOCDataGloballyinEffect, are added
473+
// to ExplicitlySpecifiedGlobals.
474+
llvm::StringSet<> ExplicitlySpecifiedGlobals;
475+
for (const auto Arg :
476+
Args.filtered(options::OPT_mtocdata_EQ, options::OPT_mno_tocdata_EQ)) {
477+
TOCDataSetting ArgTocDataSetting =
478+
Arg->getOption().matches(options::OPT_mtocdata_EQ) ? DataInTOC
479+
: AddressInTOC;
480+
481+
if (ArgTocDataSetting != DefaultTocDataSetting)
482+
for (const char *Val : Arg->getValues())
483+
ExplicitlySpecifiedGlobals.insert(Val);
484+
else
485+
for (const char *Val : Arg->getValues())
486+
ExplicitlySpecifiedGlobals.erase(Val);
487+
}
488+
489+
auto buildExceptionList = [](const llvm::StringSet<> &ExplicitValues,
490+
const char *OptionSpelling) {
491+
std::string Option(OptionSpelling);
492+
bool IsFirst = true;
493+
for (const auto &E : ExplicitValues) {
494+
if (!IsFirst)
495+
Option += ",";
496+
497+
IsFirst = false;
498+
Option += E.first();
499+
}
500+
return Option;
501+
};
502+
503+
// Pass the final tocdata options to CC1 consisting of the default
504+
// tocdata option (-mtocdata/-mno-tocdata) along with the list
505+
// option (-mno-tocdata=/-mtocdata=) if there are any explicitly specified
506+
// variables which would be exceptions to the default setting.
507+
const char *TocDataGlobalOption =
508+
TOCDataGloballyinEffect ? "-mtocdata" : "-mno-tocdata";
509+
CC1Args.push_back(TocDataGlobalOption);
510+
511+
const char *TocDataListOption =
512+
TOCDataGloballyinEffect ? "-mno-tocdata=" : "-mtocdata=";
513+
if (!ExplicitlySpecifiedGlobals.empty())
514+
CC1Args.push_back(Args.MakeArgString(llvm::Twine(
515+
buildExceptionList(ExplicitlySpecifiedGlobals, TocDataListOption))));
516+
}
517+
436518
void AIX::addClangTargetOptions(
437519
const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CC1Args,
438520
Action::OffloadKind DeviceOffloadingKind) const {
439521
Args.AddLastArg(CC1Args, options::OPT_mignore_xcoff_visibility);
440522
Args.AddLastArg(CC1Args, options::OPT_mdefault_visibility_export_mapping_EQ);
441523
Args.addOptInFlag(CC1Args, options::OPT_mxcoff_roptr, options::OPT_mno_xcoff_roptr);
442524

525+
// Forward last mtocdata/mno_tocdata options to -cc1.
526+
if (Args.hasArg(options::OPT_mtocdata_EQ, options::OPT_mno_tocdata_EQ,
527+
options::OPT_mtocdata))
528+
addTocDataOptions(Args, CC1Args, getDriver());
529+
443530
if (Args.hasFlag(options::OPT_fxl_pragma_pack,
444531
options::OPT_fno_xl_pragma_pack, true))
445532
CC1Args.push_back("-fxl-pragma-pack");

clang/lib/Frontend/CompilerInstance.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1047,6 +1047,11 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) {
10471047
if (getFrontendOpts().ShowStats || !getFrontendOpts().StatsFile.empty())
10481048
llvm::EnableStatistics(false);
10491049

1050+
// Sort vectors containing toc data and no toc data variables to facilitate
1051+
// binary search later.
1052+
llvm::sort(getCodeGenOpts().TocDataVarsUserSpecified);
1053+
llvm::sort(getCodeGenOpts().NoTocDataVars);
1054+
10501055
for (const FrontendInputFile &FIF : getFrontendOpts().Inputs) {
10511056
// Reset the ID tables if we are reusing the SourceManager and parsing
10521057
// regular files.

0 commit comments

Comments
 (0)