Skip to content

Commit dced11b

Browse files
author
Zaara Syeda
committed
[AIX][TOC] Add -mtocdata/-mno-tocdata options on AIX
This patch enables support that the XL compiler had for AIX under -qdatalocal/-qdataimported.
1 parent efac016 commit dced11b

File tree

22 files changed

+655
-17
lines changed

22 files changed

+655
-17
lines changed

clang/docs/UsersManual.rst

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4028,7 +4028,63 @@ Clang expects the GCC executable "gcc.exe" compiled for
40284028

40294029
AIX
40304030
^^^
4031+
TOC Data Transformation
4032+
"""""""""""""""""""""""
4033+
TOC data transformation is off by default (``-mno-tocdata``).
4034+
When ``-mtocdata`` is specified, the TOC data transformation will be applied to
4035+
all suitable variables with static storage duration, including static data
4036+
members of classes and block-scope static variables (if not marked as exceptions,
4037+
see further below).
40314038

4039+
Suitable variables must:
4040+
4041+
- have complete types
4042+
- be independently generated (i.e., not placed in a pool)
4043+
- be at most as large as a pointer
4044+
- not be aligned more strictly than a pointer
4045+
- not be structs containing flexible array members
4046+
- not have internal linkage
4047+
- not have aliases
4048+
- not have section attributes
4049+
4050+
The TOC data transformation results in the variable, not its address,
4051+
being placed in the TOC. This eliminates the need to load the address of the
4052+
variable from the TOC.
4053+
4054+
Note:
4055+
If the TOC data transformation is applied to a variable whose definition
4056+
is imported, the linker will generate fixup code for reading or writing to the
4057+
variable.
4058+
4059+
Any internal linkage variables specified to any TOC data options will be ignored.
4060+
4061+
**Options:**
4062+
4063+
.. option:: -mno-tocdata
4064+
4065+
This is the default behaviour. Only variables explicitly specified with
4066+
``-mtocdata=`` will have the TOC data transformation applied.
4067+
4068+
.. option:: -mtocdata
4069+
4070+
Apply the TOC data transformation to all suitable variables with static
4071+
storage duration (including static data members of classes and block-scope
4072+
static variables) that are not explicitly specified with ``-mno-tocdata=``.
4073+
4074+
.. option:: -mno-tocdata=
4075+
4076+
Can be used in conjunction with ``-mtocdata`` to mark the comma-separated
4077+
list of external linkage variables, specified using their mangled names, as
4078+
exceptions to ``-mtocdata``.
4079+
4080+
.. option:: -mtocdata=
4081+
4082+
Apply the TOC data transformation to the comma-separated list of external
4083+
linkage variables, specified using their mangled names, if they are suitable.
4084+
Emit diagnostics for all unsuitable variables specified.
4085+
4086+
Default Visibility Export Mapping
4087+
"""""""""""""""""""""""""""""""""
40324088
The ``-mdefault-visibility-export-mapping=`` option can be used to control
40334089
mapping of default visibility to an explicit shared object export
40344090
(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
@@ -403,6 +403,15 @@ class CodeGenOptions : public CodeGenOptionsBase {
403403

404404
/// List of pass builder callbacks.
405405
std::vector<std::function<void(llvm::PassBuilder &)>> PassBuilderCallbacks;
406+
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;
406415

407416
/// Path to allowlist file specifying which objects
408417
/// (files, functions) should exclusively be instrumented

clang/include/clang/Basic/DiagnosticDriverKinds.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,9 @@ def warn_drv_unsupported_gpopt : Warning<
579579
"ignoring '-mgpopt' option as it cannot be used with %select{|the implicit"
580580
" usage of }0-mabicalls">,
581581
InGroup<UnsupportedGPOpt>;
582+
def warn_drv_unsupported_tocdata: Warning<
583+
"ignoring '-mtocdata' as it is only supported for -mcmodel=small">,
584+
InGroup<OptionIgnored>;
582585
def warn_drv_unsupported_sdata : Warning<
583586
"ignoring '-msmall-data-limit=' with -mcmodel=large for -fpic or RV64">,
584587
InGroup<OptionIgnored>;

clang/include/clang/Basic/DiagnosticFrontendKinds.td

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

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

clang/include/clang/Driver/Options.td

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3520,6 +3520,29 @@ def fpass_plugin_EQ : Joined<["-"], "fpass-plugin=">,
35203520
MetaVarName<"<dsopath>">,
35213521
HelpText<"Load pass plugin from a dynamic shared object file (only with new pass manager).">,
35223522
MarshallingInfoStringVector<CodeGenOpts<"PassPlugins">>;
3523+
def mtocdata : Flag<["-"], "mtocdata">,
3524+
Visibility<[ClangOption, CLOption, DXCOption, CC1Option]>,
3525+
Flags<[TargetSpecific]>,
3526+
HelpText<"All suitable variables will have the TOC data transformation applied.">,
3527+
MarshallingInfoFlag<CodeGenOpts<"AllTocData">>;
3528+
def mno_tocdata : Flag<["-"], "mno-tocdata">,
3529+
Visibility<[ClangOption, CLOption, DXCOption, CC1Option]>,
3530+
Flags<[TargetSpecific]>,
3531+
HelpText<"This is the default. TOC data transformation is not applied to any"
3532+
"variables. Only variables specified explicitly in -mtocdata= will"
3533+
"have the TOC data transformation.">;
3534+
def mtocdata_EQ : CommaJoined<["-"], "mtocdata=">,
3535+
Visibility<[ClangOption, CLOption, DXCOption, CC1Option]>,
3536+
Flags<[TargetSpecific]>,
3537+
HelpText<"Specifies a list of variables to which the TOC data transformation"
3538+
"will be applied.">,
3539+
MarshallingInfoStringVector<CodeGenOpts<"TocDataVarsUserSpecified">>;
3540+
def mno_tocdata_EQ : CommaJoined<["-"], "mno-tocdata=">,
3541+
Visibility<[ClangOption, CLOption, DXCOption, CC1Option]>,
3542+
Flags<[TargetSpecific]>,
3543+
HelpText<"Specifies a list of variables to be exempt from the TOC data"
3544+
"transformation.">,
3545+
MarshallingInfoStringVector<CodeGenOpts<"NoTocDataVars">>;
35233546
defm preserve_as_comments : BoolFOption<"preserve-as-comments",
35243547
CodeGenOpts<"PreserveAsmComments">, DefaultTrue,
35253548
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: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -623,6 +623,28 @@ static bool checkAliasedGlobal(
623623
return true;
624624
}
625625

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

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

clang/lib/CodeGen/Targets/PPC.cpp

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

clang/lib/Driver/ToolChains/AIX.cpp

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,13 +429,102 @@ void AIX::AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
429429
llvm_unreachable("Unexpected C++ library type; only libc++ is supported.");
430430
}
431431

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

523+
// Forward last mtocdata/mno_tocdata options to -cc1.
524+
if (Args.hasArg(options::OPT_mtocdata_EQ, options::OPT_mno_tocdata_EQ,
525+
options::OPT_mtocdata))
526+
addTocDataOptions(Args, CC1Args, getDriver());
527+
439528
if (Args.hasFlag(options::OPT_fxl_pragma_pack,
440529
options::OPT_fno_xl_pragma_pack, true))
441530
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)