mirror of
https://github.com/intel/llvm.git
synced 2026-01-26 12:26:52 +08:00
[AIX][TOC] Add -mtocdata/-mno-tocdata options on AIX (#67999)
This patch enables support that the XL compiler had for AIX under -qdatalocal/-qdataimported.
This commit is contained in:
@@ -4227,7 +4227,68 @@ 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
|
||||
- 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
|
||||
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.
|
||||
|
||||
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
|
||||
|
||||
Names of variables not having external linkage 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:
|
||||
|
||||
@@ -404,6 +404,15 @@ public:
|
||||
/// 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
|
||||
/// by sanitizer coverage pass.
|
||||
|
||||
@@ -587,6 +587,9 @@ def warn_drv_unsupported_gpopt : Warning<
|
||||
"ignoring '-mgpopt' option as it cannot be used with %select{|the implicit"
|
||||
" usage of }0-mabicalls">,
|
||||
InGroup<UnsupportedGPOpt>;
|
||||
def warn_drv_unsupported_tocdata: Warning<
|
||||
"ignoring '-mtocdata' as it is only supported for -mcmodel=small">,
|
||||
InGroup<OptionIgnored>;
|
||||
def warn_drv_unsupported_sdata : Warning<
|
||||
"ignoring '-msmall-data-limit=' with -mcmodel=large for -fpic or RV64">,
|
||||
InGroup<OptionIgnored>;
|
||||
|
||||
@@ -94,6 +94,8 @@ def err_fe_backend_error_attr :
|
||||
def warn_fe_backend_warning_attr :
|
||||
Warning<"call to '%0' declared with 'warning' attribute: %1">, BackendInfo,
|
||||
InGroup<BackendWarningAttributes>;
|
||||
def warn_toc_unsupported_type : Warning<"-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;
|
||||
|
||||
@@ -3609,6 +3609,27 @@ 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">>;
|
||||
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<[TargetSpecific], [ClangOption, CLOption]>>, Group<m_Group>;
|
||||
def mtocdata_EQ : CommaJoined<["-"], "mtocdata=">,
|
||||
Visibility<[ClangOption, CC1Option]>,
|
||||
Flags<[TargetSpecific]>, Group<m_Group>,
|
||||
HelpText<"Specifies a list of variables to which the TOC data transformation"
|
||||
"will be applied.">,
|
||||
MarshallingInfoStringVector<CodeGenOpts<"TocDataVarsUserSpecified">>;
|
||||
def mno_tocdata_EQ : CommaJoined<["-"], "mno-tocdata=">,
|
||||
Visibility<[ClangOption, CC1Option]>,
|
||||
Flags<[TargetSpecific]>, Group<m_Group>,
|
||||
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],
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -626,6 +626,26 @@ 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->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)
|
||||
<< GVId << "the variable has an alias";
|
||||
}
|
||||
llvm::AttributeSet CurrAttributes = GVar->getAttributes();
|
||||
llvm::AttributeSet NewAttributes =
|
||||
CurrAttributes.removeAttribute(GVar->getContext(), "toc-data");
|
||||
GVar->setAttributes(NewAttributes);
|
||||
}
|
||||
}
|
||||
|
||||
void CodeGenModule::checkAliases() {
|
||||
// Check if the constructed aliases are well formed. It is really unfortunate
|
||||
// that we have to do this in CodeGen, but we only construct mangled names
|
||||
@@ -652,6 +672,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();
|
||||
|
||||
@@ -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 @@ public:
|
||||
|
||||
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,61 @@ 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 (!isa<llvm::GlobalVariable>(GV))
|
||||
return;
|
||||
|
||||
auto *GVar = dyn_cast<llvm::GlobalVariable>(GV);
|
||||
auto GVId = GV->getName();
|
||||
|
||||
// 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;
|
||||
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 =
|
||||
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,
|
||||
"variable has a section attribute");
|
||||
else if (GV->hasExternalLinkage() ||
|
||||
(M.getCodeGenOpts().AllTocData && !GV->hasLocalLinkage()))
|
||||
GVar->addAttribute("toc-data");
|
||||
}
|
||||
}
|
||||
|
||||
// PowerPC-32
|
||||
namespace {
|
||||
/// PPC32_SVR4_ABIInfo - The 32-bit PowerPC ELF (SVR4) ABI information.
|
||||
|
||||
@@ -433,6 +433,88 @@ 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 (const Arg *LastArg =
|
||||
Args.getLastArg(options::OPT_mtocdata, options::OPT_mno_tocdata))
|
||||
return LastArg->getOption().matches(options::OPT_mtocdata);
|
||||
else
|
||||
return false;
|
||||
}();
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
auto buildExceptionList = [](const llvm::StringSet<> &ExplicitValues,
|
||||
const char *OptionSpelling) {
|
||||
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";
|
||||
CC1Args.push_back(TocDataGlobalOption);
|
||||
|
||||
const char *TocDataListOption =
|
||||
TOCDataGloballyinEffect ? "-mno-tocdata=" : "-mtocdata=";
|
||||
if (!ExplicitlySpecifiedGlobals.empty())
|
||||
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 {
|
||||
@@ -440,6 +522,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");
|
||||
|
||||
@@ -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.
|
||||
|
||||
50
clang/test/CodeGen/PowerPC/toc-data-attribute.c
Normal file
50
clang/test/CodeGen/PowerPC/toc-data-attribute.c
Normal file
@@ -0,0 +1,50 @@
|
||||
// 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=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;
|
||||
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
|
||||
// CHECK64: @g = global i64 5, align 8 #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
|
||||
// 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
|
||||
// COMMON: @n = thread_local global i32 0, align 4
|
||||
// COMMON: @p = external global [0 x i32], align 4
|
||||
// COMMON: attributes #0 = { "toc-data" }
|
||||
39
clang/test/CodeGen/PowerPC/toc-data-attribute.cpp
Normal file
39
clang/test/CodeGen/PowerPC/toc-data-attribute.cpp
Normal file
@@ -0,0 +1,39 @@
|
||||
// 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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// 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" }
|
||||
68
clang/test/CodeGen/PowerPC/toc-data-diagnostics.c
Normal file
68
clang/test/CodeGen/PowerPC/toc-data-diagnostics.c
Normal file
@@ -0,0 +1,68 @@
|
||||
// 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 {{-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 variable has 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 {{-mtocdata option is ignored for g 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 {{-mtocdata option is ignored for t3 because it contains a flexible array member}}
|
||||
|
||||
int globalOneWithAlias = 10;
|
||||
__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;
|
||||
|
||||
|
||||
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" }
|
||||
65
clang/test/CodeGen/PowerPC/toc-data-structs-arrays.cpp
Normal file
65
clang/test/CodeGen/PowerPC/toc-data-structs-arrays.cpp
Normal file
@@ -0,0 +1,65 @@
|
||||
// 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: @e = global [5 x i16] zeroinitializer, align 2
|
||||
// CHECK64: attributes #0 = { "toc-data" }
|
||||
30
clang/test/Driver/toc-conf.c
Normal file
30
clang/test/Driver/toc-conf.c
Normal file
@@ -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"
|
||||
16
clang/test/Driver/tocdata-cc1.c
Normal file
16
clang/test/Driver/tocdata-cc1.c
Normal file
@@ -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
|
||||
@@ -1945,6 +1945,19 @@ auto partition(R &&Range, UnaryPredicate P) {
|
||||
return std::partition(adl_begin(Range), adl_end(Range), P);
|
||||
}
|
||||
|
||||
/// Provide wrappers to std::binary_search which take ranges instead of having
|
||||
/// to pass begin/end explicitly.
|
||||
template <typename R, typename T> auto binary_search(R &&Range, T &&Value) {
|
||||
return std::binary_search(adl_begin(Range), adl_end(Range),
|
||||
std::forward<T>(Value));
|
||||
}
|
||||
|
||||
template <typename R, typename T, typename Compare>
|
||||
auto binary_search(R &&Range, T &&Value, Compare C) {
|
||||
return std::binary_search(adl_begin(Range), adl_end(Range),
|
||||
std::forward<T>(Value), C);
|
||||
}
|
||||
|
||||
/// Provide wrappers to std::lower_bound which take ranges instead of having to
|
||||
/// pass begin/end explicitly.
|
||||
template <typename R, typename T> auto lower_bound(R &&Range, T &&Value) {
|
||||
|
||||
@@ -87,8 +87,7 @@ void MCSectionXCOFF::printSwitchToSection(const MCAsmInfo &MAI, const Triple &T,
|
||||
if (getKind().isCommon() && !getKind().isBSSLocal())
|
||||
return;
|
||||
|
||||
assert((getKind().isBSSExtern() || getKind().isBSSLocal()) &&
|
||||
"Unexepected section kind for toc-data");
|
||||
assert(getKind().isBSS() && "Unexpected section kind for toc-data");
|
||||
printCsectDirective(OS);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2659,6 +2659,8 @@ 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")) {
|
||||
unsigned PointerSize = GV->getParent()->getDataLayout().getPointerSize();
|
||||
Subtarget->tocDataChecks(PointerSize, GV);
|
||||
TOCDataGlobalVars.push_back(GV);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -521,40 +521,6 @@ 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 (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->hasPrivateLinkage())
|
||||
report_fatal_error("A GlobalVariable with private linkage is not "
|
||||
"currently supported by the toc data transformation.");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -185,6 +185,28 @@ 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->hasPrivateLinkage())
|
||||
report_fatal_error("A GlobalVariable with private linkage is not "
|
||||
"currently supported by the toc data transformation.");
|
||||
}
|
||||
|
||||
bool PPCSubtarget::isGVIndirectSymbol(const GlobalValue *GV) const {
|
||||
// Large code model always uses the TOC even for local symbols.
|
||||
if (TM.getCodeModel() == CodeModel::Large)
|
||||
|
||||
@@ -245,6 +245,8 @@ public:
|
||||
/// True if the GV will be accessed via an indirect symbol.
|
||||
bool isGVIndirectSymbol(const GlobalValue *GV) const;
|
||||
|
||||
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
|
||||
|
||||
16
llvm/test/CodeGen/PowerPC/toc-data-large-array.ll
Normal file
16
llvm/test/CodeGen/PowerPC/toc-data-large-array.ll
Normal file
@@ -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.
|
||||
8
llvm/test/CodeGen/PowerPC/toc-data-large-array2.ll
Normal file
8
llvm/test/CodeGen/PowerPC/toc-data-large-array2.ll
Normal file
@@ -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
|
||||
|
||||
@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.
|
||||
110
llvm/test/CodeGen/PowerPC/toc-data-struct-array.ll
Normal file
110
llvm/test/CodeGen/PowerPC/toc-data-struct-array.ll
Normal file
@@ -0,0 +1,110 @@
|
||||
; 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
|
||||
@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
|
||||
|
||||
; OBJ32: Symbol {
|
||||
; OBJ32: Name: a
|
||||
; OBJ32-NEXT: Value (RelocatableAddress): 0x3C
|
||||
; OBJ32-NEXT: Section: .data
|
||||
; OBJ32-NEXT: Type: 0x0
|
||||
; OBJ32-NEXT: StorageClass: C_EXT (0x2)
|
||||
; OBJ32-NEXT: NumberOfAuxEntries: 1
|
||||
; OBJ32-NEXT: CSECT Auxiliary Entry {
|
||||
; OBJ32-NEXT: Index: {{[0-9]+}}
|
||||
; 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: 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: {{[0-9]+}}
|
||||
; 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: 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: {{[0-9]+}}
|
||||
; 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: 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: {{[0-9]+}}
|
||||
; 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: }
|
||||
Reference in New Issue
Block a user