Add IR support, ELF section and user documentation for partitioning feature.

The partitioning feature was proposed here:
http://lists.llvm.org/pipermail/llvm-dev/2019-February/130583.html

This is mostly just documentation. The feature itself will be contributed
in subsequent patches.

Differential Revision: https://reviews.llvm.org/D60242

llvm-svn: 361923
This commit is contained in:
Peter Collingbourne 2019-05-29 03:29:01 +00:00
parent 10c548cdfa
commit 31fda09b2d
23 changed files with 470 additions and 8 deletions

117
lld/docs/Partitions.rst Normal file
View File

@ -0,0 +1,117 @@
Partitions
==========
.. warning::
This feature has not yet fully landed in LLD. This document describes how
the feature is intended to work once it lands. Furthermore, the feature
is currently experimental, and its interface is subject to change.
LLD's partitioning feature allows a program (which may be an executable
or a shared library) to be split into multiple pieces, or partitions. A
partitioned program consists of a main partition together with a number of
loadable partitions. The loadable partitions depend on the main partition
in a similar way to a regular ELF shared object dependency, but unlike a
shared object, the main partition and the loadable partitions share a virtual
address space at link time, and each loadable partition is assigned a fixed
offset from the main partition. This allows the loadable partitions to refer
to code and data in the main partition directly without the binary size and
performance overhead of PLTs, GOTs or symbol table entries.
Usage
-----
A program that uses the partitioning feature must decide which symbols are
going to be used as the "entry points" for each partition. An entry point
could, for example, be the equivalent of the partition's ``main`` function, or
there could be a group of functions that expose the functionality implemented
by the partition. The intent is that in order to use a loadable partition,
the program will use ``dlopen``/``dlsym`` or similar functions to dynamically
load the partition at its assigned address, look up an entry point by name
and call it. Note, however, that the standard ``dlopen`` function does not
allow specifying a load address. On Android, the ``android_dlopen_ext``
function may be used together with the ``ANDROID_DLEXT_RESERVED_ADDRESS``
flag to load a shared object at a specific address.
Once the entry points have been decided, the translation unit(s)
containing the entry points should be compiled using the Clang compiler flag
``-fsymbol-partition=<soname>``, where ``<soname>`` is the intended soname
of the partition. The resulting object files are passed to the linker in
the usual way.
The linker will then use these entry points to automatically split the program
into partitions according to which sections of the program are reachable from
which entry points, similarly to how ``--gc-sections`` removes unused parts of
a program. Any sections that are only reachable from a loadable partition's
entry point are assigned to that partition, while all other sections are
assigned to the main partition, including sections only reachable from
loadable partitions.
The following diagram illustrates how sections are assigned to partitions. Each
section is colored according to its assigned partition.
.. image:: partitions.svg
The result of linking a program that uses partitions is essentially an
ELF file with all of the partitions concatenated together. This file is
referred to as a combined output file. To extract a partition from the
combined output file, the ``llvm-objcopy`` tool should be used together
with the flag ``--extract-main-partition`` to extract the main partition, or
``-extract-partition=<soname>`` to extract one of the loadable partitions.
An example command sequence is shown below:
.. code-block:: shell
# Compile the main program.
clang -ffunction-sections -fdata-sections -c main.c
# Compile a feature to be placed in a loadable partition.
# Note that this is likely to be a separate build step to the main partition.
clang -ffunction-sections -fdata-sections -fsymbol-partition=libfeature.so -c feature.c
# Link the combined output file.
clang main.o feature.o -fuse-ld=lld -shared -o libcombined.so -Wl,-soname,libmain.so -Wl,--gc-sections
# Extract the partitions.
llvm-objcopy libcombined.so libmain.so --extract-main-partition
llvm-objcopy libcombined.so libfeature.so --extract-partition=libfeature.so
In order to allow a program to discover the names of its loadable partitions
and the locations of their reserved regions, the linker creates a partition
index, which is an array of structs with the following definition:
.. code-block:: c
struct partition_index_entry {
int32_t name_offset;
int32_t addr_offset;
uint32_t size;
};
The ``name_offset`` field is a relative pointer to a null-terminated string
containing the soname of the partition, the ``addr_offset`` field is a
relative pointer to its load address and the ``size`` field contains the
size of the region reserved for the partition. To derive an absolute pointer
from the relative pointer fields in this data structure, the address of the
field should be added to the value stored in the field.
The program may discover the location of the partition index using the
linker-defined symbols ``__part_index_begin`` and ``__part_index_end``.
Restrictions
------------
This feature is currently only supported in the ELF linker.
The partitioning feature may not currently be used together with the
``SECTIONS`` or ``PHDRS`` linker script features, nor may it be used with the
``--section-start``, ``-Ttext``, ``-Tdata`` or ``-Tbss`` flags. All of these
features assume a single set of output sections and/or program headers, which
makes their semantics ambiguous in the presence of more than one partition.
The partitioning feature may not currently be used on the MIPS architecture
because it is unclear whether the MIPS multi-GOT ABI is compatible with
partitions.
The current implementation only supports creating up to 254 partitions due
to implementation limitations. This limit may be relaxed in the future.

View File

@ -174,4 +174,5 @@ document soon.
WebAssembly
windows_support
missingkeyfunction
Partitions
ReleaseNotes

22
lld/docs/partitions.dot Normal file
View File

@ -0,0 +1,22 @@
digraph G {
part_main [label="Main partition",shape=plaintext];
part1 [label="Loadable partition 1",shape=plaintext];
part2 [label="Loadable partition 2",shape=plaintext];
main [style=filled,fillcolor=lightblue];
f1 [style=filled,fillcolor=lightsalmon];
f2 [style=filled,fillcolor=palegreen];
f3 [style=filled,fillcolor=lightblue];
f4 [style=filled,fillcolor=lightsalmon];
f5 [style=filled,fillcolor=lightblue];
f6 [style=filled,fillcolor=palegreen];
part_main -> main;
main -> f3;
part1 -> f1;
f1 -> f3;
f1 -> f4;
f1 -> f5;
part2 -> f2;
f2 -> f3;
f2 -> f5;
f2 -> f6;
}

110
lld/docs/partitions.svg Normal file
View File

@ -0,0 +1,110 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Generated by graphviz version 2.38.0 (20140413.2041)
-->
<!-- Title: G Pages: 1 -->
<svg width="393pt" height="188pt"
viewBox="0.00 0.00 393.00 188.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 184)">
<title>G</title>
<polygon fill="white" stroke="none" points="-4,4 -4,-184 389,-184 389,4 -4,4"/>
<!-- part_main -->
<g id="node1" class="node"><title>part_main</title>
<text text-anchor="middle" x="47.5" y="-158.3" font-family="Times,serif" font-size="14.00">Main partition</text>
</g>
<!-- main -->
<g id="node4" class="node"><title>main</title>
<ellipse fill="lightblue" stroke="black" cx="75.5" cy="-90" rx="28.6953" ry="18"/>
<text text-anchor="middle" x="75.5" y="-86.3" font-family="Times,serif" font-size="14.00">main</text>
</g>
<!-- part_main&#45;&gt;main -->
<g id="edge1" class="edge"><title>part_main&#45;&gt;main</title>
<path fill="none" stroke="black" d="M54.4214,-143.697C57.6218,-135.696 61.492,-126.02 65.0381,-117.155"/>
<polygon fill="black" stroke="black" points="68.3868,-118.207 68.8511,-107.622 61.8874,-115.607 68.3868,-118.207"/>
</g>
<!-- part1 -->
<g id="node2" class="node"><title>part1</title>
<text text-anchor="middle" x="176.5" y="-158.3" font-family="Times,serif" font-size="14.00">Loadable partition 1</text>
</g>
<!-- f1 -->
<g id="node5" class="node"><title>f1</title>
<ellipse fill="lightsalmon" stroke="black" cx="176.5" cy="-90" rx="27" ry="18"/>
<text text-anchor="middle" x="176.5" y="-86.3" font-family="Times,serif" font-size="14.00">f1</text>
</g>
<!-- part1&#45;&gt;f1 -->
<g id="edge3" class="edge"><title>part1&#45;&gt;f1</title>
<path fill="none" stroke="black" d="M176.5,-143.697C176.5,-135.983 176.5,-126.712 176.5,-118.112"/>
<polygon fill="black" stroke="black" points="180,-118.104 176.5,-108.104 173,-118.104 180,-118.104"/>
</g>
<!-- part2 -->
<g id="node3" class="node"><title>part2</title>
<text text-anchor="middle" x="321.5" y="-158.3" font-family="Times,serif" font-size="14.00">Loadable partition 2</text>
</g>
<!-- f2 -->
<g id="node6" class="node"><title>f2</title>
<ellipse fill="palegreen" stroke="black" cx="284.5" cy="-90" rx="27" ry="18"/>
<text text-anchor="middle" x="284.5" y="-86.3" font-family="Times,serif" font-size="14.00">f2</text>
</g>
<!-- part2&#45;&gt;f2 -->
<g id="edge7" class="edge"><title>part2&#45;&gt;f2</title>
<path fill="none" stroke="black" d="M312.354,-143.697C307.97,-135.403 302.636,-125.311 297.813,-116.187"/>
<polygon fill="black" stroke="black" points="300.801,-114.35 293.034,-107.145 294.612,-117.621 300.801,-114.35"/>
</g>
<!-- f3 -->
<g id="node7" class="node"><title>f3</title>
<ellipse fill="lightblue" stroke="black" cx="104.5" cy="-18" rx="27" ry="18"/>
<text text-anchor="middle" x="104.5" y="-14.3" font-family="Times,serif" font-size="14.00">f3</text>
</g>
<!-- main&#45;&gt;f3 -->
<g id="edge2" class="edge"><title>main&#45;&gt;f3</title>
<path fill="none" stroke="black" d="M82.3726,-72.411C85.7675,-64.2164 89.9422,-54.1395 93.7473,-44.9548"/>
<polygon fill="black" stroke="black" points="97.0828,-46.0481 97.6767,-35.4699 90.6158,-43.3689 97.0828,-46.0481"/>
</g>
<!-- f1&#45;&gt;f3 -->
<g id="edge4" class="edge"><title>f1&#45;&gt;f3</title>
<path fill="none" stroke="black" d="M161.93,-74.8345C151.75,-64.9376 137.976,-51.5462 126.469,-40.3591"/>
<polygon fill="black" stroke="black" points="128.905,-37.8461 119.296,-33.3847 124.026,-42.865 128.905,-37.8461"/>
</g>
<!-- f4 -->
<g id="node8" class="node"><title>f4</title>
<ellipse fill="lightsalmon" stroke="black" cx="176.5" cy="-18" rx="27" ry="18"/>
<text text-anchor="middle" x="176.5" y="-14.3" font-family="Times,serif" font-size="14.00">f4</text>
</g>
<!-- f1&#45;&gt;f4 -->
<g id="edge5" class="edge"><title>f1&#45;&gt;f4</title>
<path fill="none" stroke="black" d="M176.5,-71.6966C176.5,-63.9827 176.5,-54.7125 176.5,-46.1124"/>
<polygon fill="black" stroke="black" points="180,-46.1043 176.5,-36.1043 173,-46.1044 180,-46.1043"/>
</g>
<!-- f5 -->
<g id="node9" class="node"><title>f5</title>
<ellipse fill="lightblue" stroke="black" cx="248.5" cy="-18" rx="27" ry="18"/>
<text text-anchor="middle" x="248.5" y="-14.3" font-family="Times,serif" font-size="14.00">f5</text>
</g>
<!-- f1&#45;&gt;f5 -->
<g id="edge6" class="edge"><title>f1&#45;&gt;f5</title>
<path fill="none" stroke="black" d="M191.07,-74.8345C201.25,-64.9376 215.024,-51.5462 226.531,-40.3591"/>
<polygon fill="black" stroke="black" points="228.974,-42.865 233.704,-33.3847 224.095,-37.8461 228.974,-42.865"/>
</g>
<!-- f2&#45;&gt;f3 -->
<g id="edge8" class="edge"><title>f2&#45;&gt;f3</title>
<path fill="none" stroke="black" d="M260.806,-81.0022C232.063,-71.1346 182.266,-53.5073 140.5,-36 138.683,-35.2385 136.825,-34.4358 134.957,-33.6106"/>
<polygon fill="black" stroke="black" points="136.231,-30.3452 125.68,-29.3829 133.328,-36.7149 136.231,-30.3452"/>
</g>
<!-- f2&#45;&gt;f5 -->
<g id="edge9" class="edge"><title>f2&#45;&gt;f5</title>
<path fill="none" stroke="black" d="M276.15,-72.7646C271.788,-64.2831 266.353,-53.7144 261.459,-44.1974"/>
<polygon fill="black" stroke="black" points="264.49,-42.4395 256.804,-35.1473 258.265,-45.6409 264.49,-42.4395"/>
</g>
<!-- f6 -->
<g id="node10" class="node"><title>f6</title>
<ellipse fill="palegreen" stroke="black" cx="320.5" cy="-18" rx="27" ry="18"/>
<text text-anchor="middle" x="320.5" y="-14.3" font-family="Times,serif" font-size="14.00">f6</text>
</g>
<!-- f2&#45;&gt;f6 -->
<g id="edge10" class="edge"><title>f2&#45;&gt;f6</title>
<path fill="none" stroke="black" d="M292.85,-72.7646C297.212,-64.2831 302.647,-53.7144 307.541,-44.1974"/>
<polygon fill="black" stroke="black" points="310.735,-45.6409 312.196,-35.1473 304.51,-42.4395 310.735,-45.6409"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.8 KiB

View File

@ -379,6 +379,22 @@ this directive, all symbols are considered address-significant.
This marks ``sym`` as address-significant.
``SHT_LLVM_SYMPART`` Section (symbol partition specification)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This section is used to mark symbols with the `partition`_ that they
belong to. An ``.llvm_sympart`` section consists of a null-terminated string
specifying the name of the partition followed by a relocation referring to
the symbol that belongs to the partition. It may be constructed as follows:
.. code-block:: gas
.section ".llvm_sympart","",@llvm_sympart
.asciz "libpartition.so"
.word symbol_in_partition
.. _partition: https://lld.llvm.org/Partitions.html
CodeView-Dependent
------------------

View File

@ -842,6 +842,7 @@ enum : unsigned {
SHT_LLVM_ADDRSIG = 0x6fff4c03, // List of address-significant symbols
// for safe ICF.
SHT_LLVM_DEPENDENT_LIBRARIES = 0x6fff4c04, // LLVM Dependent Library Specifiers.
SHT_LLVM_SYMPART = 0x6fff4c05, // Symbol partition specification.
// Android's experimental support for SHT_RELR sections.
// https://android.googlesource.com/platform/bionic/+/b7feec74547f84559a1467aca02708ff61346d2a/libc/include/elf.h#512
SHT_ANDROID_RELR = 0x6fffff00, // Relocation entries; only offsets.

View File

@ -79,15 +79,15 @@ protected:
ValueType(Ty), Visibility(DefaultVisibility),
UnnamedAddrVal(unsigned(UnnamedAddr::None)),
DllStorageClass(DefaultStorageClass), ThreadLocal(NotThreadLocal),
HasLLVMReservedName(false), IsDSOLocal(false), IntID((Intrinsic::ID)0U),
Parent(nullptr) {
HasLLVMReservedName(false), IsDSOLocal(false), HasPartition(false),
IntID((Intrinsic::ID)0U), Parent(nullptr) {
setLinkage(Linkage);
setName(Name);
}
Type *ValueType;
static const unsigned GlobalValueSubClassDataBits = 17;
static const unsigned GlobalValueSubClassDataBits = 16;
// All bitfields use unsigned as the underlying type so that MSVC will pack
// them.
@ -108,9 +108,13 @@ protected:
/// definition cannot be runtime preempted.
unsigned IsDSOLocal : 1;
/// True if this symbol has a partition name assigned (see
/// https://lld.llvm.org/Partitions.html).
unsigned HasPartition : 1;
private:
// Give subclasses access to what otherwise would be wasted padding.
// (17 + 4 + 2 + 2 + 2 + 3 + 1 + 1) == 32.
// (16 + 4 + 2 + 2 + 2 + 3 + 1 + 1 + 1) == 32.
unsigned SubClassData : GlobalValueSubClassDataBits;
friend class Constant;
@ -280,6 +284,12 @@ public:
return IsDSOLocal;
}
bool hasPartition() const {
return HasPartition;
}
StringRef getPartition() const;
void setPartition(StringRef Part);
static LinkageTypes getLinkOnceLinkage(bool ODR) {
return ODR ? LinkOnceODRLinkage : LinkOnceAnyLinkage;
}

View File

@ -570,6 +570,7 @@ lltok::Kind LLLexer::LexIdentifier() {
KEYWORD(align);
KEYWORD(addrspace);
KEYWORD(section);
KEYWORD(partition);
KEYWORD(alias);
KEYWORD(ifunc);
KEYWORD(module);

View File

@ -856,11 +856,14 @@ static void maybeSetDSOLocal(bool DSOLocal, GlobalValue &GV) {
/// ::= GlobalVar '=' OptionalLinkage OptionalPreemptionSpecifier
/// OptionalVisibility OptionalDLLStorageClass
/// OptionalThreadLocal OptionalUnnamedAddr
// 'alias|ifunc' IndirectSymbol
/// 'alias|ifunc' IndirectSymbol IndirectSymbolAttr*
///
/// IndirectSymbol
/// ::= TypeAndValue
///
/// IndirectSymbolAttr
/// ::= ',' 'partition' StringConstant
///
/// Everything through OptionalUnnamedAddr has already been parsed.
///
bool LLParser::parseIndirectSymbol(const std::string &Name, LocTy NameLoc,
@ -960,6 +963,21 @@ bool LLParser::parseIndirectSymbol(const std::string &Name, LocTy NameLoc,
GA->setUnnamedAddr(UnnamedAddr);
maybeSetDSOLocal(DSOLocal, *GA);
// At this point we've parsed everything except for the IndirectSymbolAttrs.
// Now parse them if there are any.
while (Lex.getKind() == lltok::comma) {
Lex.Lex();
if (Lex.getKind() == lltok::kw_partition) {
Lex.Lex();
GA->setPartition(Lex.getStrVal());
if (ParseToken(lltok::StringConstant, "expected partition string"))
return true;
} else {
return TokError("unknown alias or ifunc property!");
}
}
if (Name.empty())
NumberedVals.push_back(GA.get());
@ -1095,6 +1113,11 @@ bool LLParser::ParseGlobal(const std::string &Name, LocTy NameLoc,
GV->setSection(Lex.getStrVal());
if (ParseToken(lltok::StringConstant, "expected global section string"))
return true;
} else if (Lex.getKind() == lltok::kw_partition) {
Lex.Lex();
GV->setPartition(Lex.getStrVal());
if (ParseToken(lltok::StringConstant, "expected partition string"))
return true;
} else if (Lex.getKind() == lltok::kw_align) {
unsigned Alignment;
if (ParseOptionalAlignment(Alignment)) return true;
@ -5287,6 +5310,7 @@ bool LLParser::ParseFunctionHeader(Function *&Fn, bool isDefine) {
std::vector<unsigned> FwdRefAttrGrps;
LocTy BuiltinLoc;
std::string Section;
std::string Partition;
unsigned Alignment;
std::string GC;
GlobalValue::UnnamedAddr UnnamedAddr = GlobalValue::UnnamedAddr::None;
@ -5303,6 +5327,8 @@ bool LLParser::ParseFunctionHeader(Function *&Fn, bool isDefine) {
BuiltinLoc) ||
(EatIfPresent(lltok::kw_section) &&
ParseStringConstant(Section)) ||
(EatIfPresent(lltok::kw_partition) &&
ParseStringConstant(Partition)) ||
parseOptionalComdat(FunctionName, C) ||
ParseOptionalAlignment(Alignment) ||
(EatIfPresent(lltok::kw_gc) &&
@ -5404,6 +5430,7 @@ bool LLParser::ParseFunctionHeader(Function *&Fn, bool isDefine) {
Fn->setUnnamedAddr(UnnamedAddr);
Fn->setAlignment(Alignment);
Fn->setSection(Section);
Fn->setPartition(Partition);
Fn->setComdat(C);
Fn->setPersonalityFn(PersonalityFn);
if (!GC.empty()) Fn->setGC(GC);

View File

@ -113,6 +113,7 @@ enum Kind {
kw_align,
kw_addrspace,
kw_section,
kw_partition,
kw_alias,
kw_ifunc,
kw_module,

View File

@ -2892,7 +2892,8 @@ static void inferDSOLocal(GlobalValue *GV) {
Error BitcodeReader::parseGlobalVarRecord(ArrayRef<uint64_t> Record) {
// v1: [pointer type, isconst, initid, linkage, alignment, section,
// visibility, threadlocal, unnamed_addr, externally_initialized,
// dllstorageclass, comdat, attributes, preemption specifier] (name in VST)
// dllstorageclass, comdat, attributes, preemption specifier,
// partition strtab offset, partition strtab size] (name in VST)
// v2: [strtab_offset, strtab_size, v1]
StringRef Name;
std::tie(Name, Record) = readNameFromStrtab(Record);
@ -2983,6 +2984,10 @@ Error BitcodeReader::parseGlobalVarRecord(ArrayRef<uint64_t> Record) {
}
inferDSOLocal(NewGV);
// Check whether we have enough values to read a partition name.
if (Record.size() > 15)
NewGV->setPartition(StringRef(Strtab.data() + Record[14], Record[15]));
return Error::success();
}
@ -3072,6 +3077,12 @@ Error BitcodeReader::parseFunctionRecord(ArrayRef<uint64_t> Record) {
}
inferDSOLocal(Func);
// Record[16] is the address space number.
// Check whether we have enough values to read a partition name.
if (Record.size() > 18)
Func->setPartition(StringRef(Strtab.data() + Record[17], Record[18]));
ValueList.push_back(Func);
// If this is a function with a body, remember the prototype we are
@ -3149,6 +3160,13 @@ Error BitcodeReader::parseGlobalIndirectSymbolRecord(
NewGA->setDSOLocal(getDecodedDSOLocal(Record[OpNum++]));
inferDSOLocal(NewGA);
// Check whether we have enough values to read a partition name.
if (OpNum + 1 < Record.size()) {
NewGA->setPartition(
StringRef(Strtab.data() + Record[OpNum], Record[OpNum + 1]));
OpNum += 2;
}
ValueList.push_back(NewGA);
IndirectSymbolInits.push_back(std::make_pair(NewGA, Val));
return Error::success();

View File

@ -1262,7 +1262,8 @@ void ModuleBitcodeWriter::writeModuleInfo() {
GV.getDLLStorageClass() != GlobalValue::DefaultStorageClass ||
GV.hasComdat() ||
GV.hasAttributes() ||
GV.isDSOLocal()) {
GV.isDSOLocal() ||
GV.hasPartition()) {
Vals.push_back(getEncodedVisibility(GV));
Vals.push_back(getEncodedThreadLocalMode(GV));
Vals.push_back(getEncodedUnnamedAddr(GV));
@ -1274,6 +1275,8 @@ void ModuleBitcodeWriter::writeModuleInfo() {
Vals.push_back(VE.getAttributeListID(AL));
Vals.push_back(GV.isDSOLocal());
Vals.push_back(addToStrtab(GV.getPartition()));
Vals.push_back(GV.getPartition().size());
} else {
AbbrevToUse = SimpleGVarAbbrev;
}
@ -1311,6 +1314,8 @@ void ModuleBitcodeWriter::writeModuleInfo() {
Vals.push_back(F.isDSOLocal());
Vals.push_back(F.getAddressSpace());
Vals.push_back(addToStrtab(F.getPartition()));
Vals.push_back(F.getPartition().size());
unsigned AbbrevToUse = 0;
Stream.EmitRecord(bitc::MODULE_CODE_FUNCTION, Vals, AbbrevToUse);
@ -1333,6 +1338,8 @@ void ModuleBitcodeWriter::writeModuleInfo() {
Vals.push_back(getEncodedThreadLocalMode(A));
Vals.push_back(getEncodedUnnamedAddr(A));
Vals.push_back(A.isDSOLocal());
Vals.push_back(addToStrtab(A.getPartition()));
Vals.push_back(A.getPartition().size());
unsigned AbbrevToUse = 0;
Stream.EmitRecord(bitc::MODULE_CODE_ALIAS, Vals, AbbrevToUse);
@ -1351,6 +1358,8 @@ void ModuleBitcodeWriter::writeModuleInfo() {
Vals.push_back(getEncodedLinkage(I));
Vals.push_back(getEncodedVisibility(I));
Vals.push_back(I.isDSOLocal());
Vals.push_back(addToStrtab(I.getPartition()));
Vals.push_back(I.getPartition().size());
Stream.EmitRecord(bitc::MODULE_CODE_IFUNC, Vals);
Vals.clear();
}

View File

@ -1632,6 +1632,24 @@ bool AsmPrinter::doFinalization(Module &M) {
OutStreamer->EmitAddrsigSym(getSymbol(&GV));
}
// Emit symbol partition specifications (ELF only).
if (TM.getTargetTriple().isOSBinFormatELF()) {
unsigned UniqueID = 0;
for (const GlobalValue &GV : M.global_values()) {
if (!GV.hasPartition() || GV.isDeclarationForLinker() ||
GV.getVisibility() != GlobalValue::DefaultVisibility)
continue;
OutStreamer->SwitchSection(OutContext.getELFSection(
".llvm_sympart", ELF::SHT_LLVM_SYMPART, 0, 0, "", ++UniqueID));
OutStreamer->EmitBytes(GV.getPartition());
OutStreamer->EmitZeros(1);
OutStreamer->EmitValue(
MCSymbolRefExpr::create(getSymbol(&GV), OutContext),
MAI->getCodePointerSize());
}
}
// Allow the target to emit any magic that it wants at the end of the file,
// after everything else has gone out.
EmitEndOfAsmFile(M);

View File

@ -3247,6 +3247,12 @@ void AssemblyWriter::printGlobal(const GlobalVariable *GV) {
printEscapedString(GV->getSection(), Out);
Out << '"';
}
if (GV->hasPartition()) {
Out << ", partition \"";
printEscapedString(GV->getPartition(), Out);
Out << '"';
}
maybePrintComdat(Out, *GV);
if (GV->getAlignment())
Out << ", align " << GV->getAlignment();
@ -3298,6 +3304,12 @@ void AssemblyWriter::printIndirectSymbol(const GlobalIndirectSymbol *GIS) {
writeOperand(IS, !isa<ConstantExpr>(IS));
}
if (GIS->hasPartition()) {
Out << ", partition \"";
printEscapedString(GIS->getPartition(), Out);
Out << '"';
}
printInfoComment(*GIS);
Out << '\n';
}
@ -3438,6 +3450,11 @@ void AssemblyWriter::printFunction(const Function *F) {
printEscapedString(F->getSection(), Out);
Out << '"';
}
if (F->hasPartition()) {
Out << " partition \"";
printEscapedString(F->getPartition(), Out);
Out << '"';
}
maybePrintComdat(Out, *F);
if (F->getAlignment())
Out << " align " << F->getAlignment();

View File

@ -67,6 +67,7 @@ void GlobalValue::copyAttributesFrom(const GlobalValue *Src) {
setUnnamedAddr(Src->getUnnamedAddr());
setDLLStorageClass(Src->getDLLStorageClass());
setDSOLocal(Src->isDSOLocal());
setPartition(Src->getPartition());
}
void GlobalValue::removeFromParent() {
@ -180,6 +181,28 @@ const Comdat *GlobalValue::getComdat() const {
return cast<GlobalObject>(this)->getComdat();
}
StringRef GlobalValue::getPartition() const {
if (!hasPartition())
return "";
return getContext().pImpl->GlobalValuePartitions[this];
}
void GlobalValue::setPartition(StringRef S) {
// Do nothing if we're clearing the partition and it is already empty.
if (!hasPartition() && S.empty())
return;
// Get or create a stable partition name string and put it in the table in the
// context.
if (!S.empty())
S = getContext().pImpl->Saver.save(S);
getContext().pImpl->GlobalValuePartitions[this] = S;
// Update the HasPartition field. Setting the partition to the empty string
// means this global no longer has a partition.
HasPartition = !S.empty();
}
StringRef GlobalObject::getSectionImpl() const {
assert(hasSection());
return getContext().pImpl->GlobalObjectSections[this];

View File

@ -1356,6 +1356,9 @@ public:
/// Collection of per-GlobalObject sections used in this context.
DenseMap<const GlobalObject *, StringRef> GlobalObjectSections;
/// Collection of per-GlobalValue partitions used in this context.
DenseMap<const GlobalValue *, StringRef> GlobalValuePartitions;
/// DiscriminatorTable - This table maps file:line locations to an
/// integer representing the next DWARF path discriminator to assign to
/// instructions in different blocks at the same location.

View File

@ -617,6 +617,8 @@ EndStmt:
Type = ELF::SHT_LLVM_CALL_GRAPH_PROFILE;
else if (TypeName == "llvm_dependent_libraries")
Type = ELF::SHT_LLVM_DEPENDENT_LIBRARIES;
else if (TypeName == "llvm_sympart")
Type = ELF::SHT_LLVM_SYMPART;
else if (TypeName.getAsInteger(0, Type))
return TokError("unknown section type");
}

View File

@ -154,6 +154,8 @@ void MCSectionELF::PrintSwitchToSection(const MCAsmInfo &MAI, const Triple &T,
OS << "llvm_call_graph_profile";
else if (Type == ELF::SHT_LLVM_DEPENDENT_LIBRARIES)
OS << "llvm_dependent_libraries";
else if (Type == ELF::SHT_LLVM_SYMPART)
OS << "llvm_sympart";
else
report_fatal_error("unsupported type 0x" + Twine::utohexstr(Type) +
" for section " + getSectionName());

View File

@ -254,6 +254,7 @@ StringRef llvm::object::getELFSectionTypeName(uint32_t Machine, unsigned Type) {
STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_CALL_GRAPH_PROFILE);
STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_ADDRSIG);
STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_DEPENDENT_LIBRARIES);
STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_SYMPART);
STRINGIFY_ENUM_CASE(ELF, SHT_GNU_ATTRIBUTES);
STRINGIFY_ENUM_CASE(ELF, SHT_GNU_HASH);
STRINGIFY_ENUM_CASE(ELF, SHT_GNU_verdef);

View File

@ -160,6 +160,10 @@ $comdat.samesize = comdat samesize
@g.section = global i32 0, section "_DATA"
; CHECK: @g.section = global i32 0, section "_DATA"
; Global Variables -- partition
@g.partition = global i32 0, partition "part"
; CHECK: @g.partition = global i32 0, partition "part"
; Global Variables -- comdat
@comdat.any = global i32 0, comdat
; CHECK: @comdat.any = global i32 0, comdat
@ -251,6 +255,10 @@ declare void @g.f1()
@a.local_unnamed_addr = local_unnamed_addr alias i32, i32* @g.local_unnamed_addr
; CHECK: @a.local_unnamed_addr = local_unnamed_addr alias i32, i32* @g.local_unnamed_addr
; Aliases -- partition
; CHECK: @alias.partition = alias i32, i32* @g.partition, partition "part"
@alias.partition = alias i32, i32* @g.partition, partition "part"
;; IFunc
; Format @<Name> = [Linkage] [Visibility] ifunc <IFuncTy>,
; <ResolverTy>* @<Resolver>
@ -271,6 +279,10 @@ declare void @g.f1()
@ifunc.protected = protected ifunc void (), i8* ()* @ifunc_resolver
; CHECK: @ifunc.protected = protected ifunc void (), i8* ()* @ifunc_resolver
; IFunc -- partition
; CHECK: @ifunc.partition = ifunc void (), i8* ()* @ifunc_resolver, partition "part"
@ifunc.partition = ifunc void (), i8* ()* @ifunc_resolver, partition "part"
define i8* @ifunc_resolver() {
entry:
ret i8* null
@ -620,6 +632,12 @@ declare void @f.strictfp() #35
declare void @f.section() section "80"
; CHECK: declare void @f.section() section "80"
; Functions -- partition
define void @f.partition() partition "part" {
; CHECK: define void @f.partition() partition "part"
ret void
}
; Functions -- comdat
define void @f.comdat_any() comdat($comdat.any) {
; CHECK: define void @f.comdat_any() comdat($comdat.any)

View File

@ -0,0 +1,33 @@
; RUN: llc < %s -mtriple=x86_64-unknown-linux | FileCheck %s
; CHECK: .section .llvm_sympart,"",@llvm_sympart,unique,1
; CHECK-NEXT: .ascii "part1"
; CHECK-NEXT: .zero 1
; CHECK-NEXT: .quad f1
; CHECK-NEXT: .section .llvm_sympart,"",@llvm_sympart,unique,2
; CHECK-NEXT: .ascii "part4"
; CHECK-NEXT: .zero 1
; CHECK-NEXT: .quad g1
; CHECK-NEXT: .section .llvm_sympart,"",@llvm_sympart,unique,3
; CHECK-NEXT: .ascii "part5"
; CHECK-NEXT: .zero 1
; CHECK-NEXT: .quad a1
; CHECK-NEXT: .section .llvm_sympart,"",@llvm_sympart,unique,4
; CHECK-NEXT: .ascii "part6"
; CHECK-NEXT: .zero 1
; CHECK-NEXT: .quad i1
define void @f1() partition "part1" {
unreachable
}
define hidden void @f2() partition "part2" {
unreachable
}
declare void @f3() partition "part3"
@g1 = global i32 0, partition "part4"
@a1 = alias i32, i32* @g1, partition "part5"
@i1 = ifunc void(), void()* @f1, partition "part6"

View File

@ -306,3 +306,15 @@ bar:
// CHECK-NEXT: SHF_STRINGS
// CHECK-NEXT: ]
// CHECK: }
// Test SHT_LLVM_SYMPART
.section .llvm_sympart,"",@llvm_sympart
// ASM: .section .llvm_sympart,"",@llvm_sympart
// CHECK: Section {
// CHECK: Name: .llvm_sympart
// CHECK-NEXT: Type: SHT_LLVM_SYMPART
// CHECK-NEXT: Flags [
// CHECK-NEXT: ]
// CHECK: }

View File

@ -9,7 +9,7 @@
; BCA: <SYMTAB_BLOCK
; Version stored at offset 0.
; BCA-NEXT: <BLOB abbrevid=4/> blob data = '\x02\x00\x00\x00\x06\x00\x00\x00\x08\x00\x00\x00L\x00\x00\x00\x01\x00\x00\x00X\x00\x00\x00\x00\x00\x00\x00X\x00\x00\x00\x02\x00\x00\x00\x88\x00\x00\x00\x00\x00\x00\x00\x0E\x00\x00\x00\x18\x00\x00\x00&\x00\x00\x00\x0B\x00\x00\x001\x00\x00\x00\x00\x00\x00\x00\x88\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\xFF\xFF\xFF\xFF\x00$\x00\x00\x03\x00\x00\x00\x03\x00\x00\x00\x03\x00\x00\x00\x03\x00\x00\x00\xFF\xFF\xFF\xFF\x08$\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x03\x00\x00\x00\x03\x00\x00\x00'
; BCA-NEXT: <BLOB abbrevid=4/> blob data = '\x02\x00\x00\x00\x06\x00\x00\x00\x08\x00\x00\x00L\x00\x00\x00\x01\x00\x00\x00X\x00\x00\x00\x00\x00\x00\x00X\x00\x00\x00\x02\x00\x00\x00\x88\x00\x00\x00\x00\x00\x00\x00\x0E\x00\x00\x00\x18\x00\x00\x00&\x00\x00\x00\x0B\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x88\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\xFF\xFF\xFF\xFF\x00$\x00\x00\x03\x00\x00\x00\x03\x00\x00\x00\x03\x00\x00\x00\x03\x00\x00\x00\xFF\xFF\xFF\xFF\x08$\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x03\x00\x00\x00\x03\x00\x00\x00'
; BCA-NEXT: </SYMTAB_BLOCK>
; BCA-NEXT: <STRTAB_BLOCK
; BCA-NEXT: <BLOB abbrevid=4/> blob data = 'foobarproducerx86_64-unknown-linux-gnuirsymtab.ll'