diff --git a/lld/docs/Partitions.rst b/lld/docs/Partitions.rst new file mode 100644 --- /dev/null +++ b/lld/docs/Partitions.rst @@ -0,0 +1,106 @@ +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 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, and each loadable partition is assigned a +fixed load address relative to the load address of the main partition. This +allows the loadable partitions to refer to code and data in the main partition +directly by address 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 "entry points" to 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=``, where ```` 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=`` to extract one of the loadable partitions. +An example command sequence is shown below: + +.. code-block:: shell + + $ clang -ffunction-sections -fdata-sections -c main.c + $ clang -ffunction-sections -fdata-sections -fsymbol-partition=libfeature.so -c feature.c + $ clang main.o feature.o -fuse-ld=lld -shared -o libcombined.so -Wl,-soname,libmain.so -Wl,--gc-sections + $ 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_relptr; + int32_t addr_relptr; + uint32_t size; + }; + +The ``name_relptr`` field is a relative pointer to a null-terminated string +containing the soname of the partition, the ``addr_relptr`` 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. diff --git a/lld/docs/index.rst b/lld/docs/index.rst --- a/lld/docs/index.rst +++ b/lld/docs/index.rst @@ -174,4 +174,5 @@ WebAssembly windows_support missingkeyfunction + Partitions ReleaseNotes diff --git a/lld/docs/partitions.dot b/lld/docs/partitions.dot new file mode 100644 --- /dev/null +++ b/lld/docs/partitions.dot @@ -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; +} diff --git a/lld/docs/partitions.svg b/lld/docs/partitions.svg new file mode 100644 --- /dev/null +++ b/lld/docs/partitions.svg @@ -0,0 +1,110 @@ + + + + + + +G + + +part_main +Main partition + + +main + +main + + +part_main->main + + + + +part1 +Loadable partition 1 + + +f1 + +f1 + + +part1->f1 + + + + +part2 +Loadable partition 2 + + +f2 + +f2 + + +part2->f2 + + + + +f3 + +f3 + + +main->f3 + + + + +f1->f3 + + + + +f4 + +f4 + + +f1->f4 + + + + +f5 + +f5 + + +f1->f5 + + + + +f2->f3 + + + + +f2->f5 + + + + +f6 + +f6 + + +f2->f6 + + + + + diff --git a/llvm/docs/Extensions.rst b/llvm/docs/Extensions.rst --- a/llvm/docs/Extensions.rst +++ b/llvm/docs/Extensions.rst @@ -359,6 +359,22 @@ 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 ------------------ diff --git a/llvm/include/llvm/BinaryFormat/ELF.h b/llvm/include/llvm/BinaryFormat/ELF.h --- a/llvm/include/llvm/BinaryFormat/ELF.h +++ b/llvm/include/llvm/BinaryFormat/ELF.h @@ -838,6 +838,7 @@ SHT_LLVM_CALL_GRAPH_PROFILE = 0x6fff4c02, // LLVM Call Graph Profile. SHT_LLVM_ADDRSIG = 0x6fff4c03, // List of address-significant symbols // for safe ICF. + SHT_LLVM_SYMPART = 0x6fff4c04, // 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. diff --git a/llvm/include/llvm/IR/GlobalValue.h b/llvm/include/llvm/IR/GlobalValue.h --- a/llvm/include/llvm/IR/GlobalValue.h +++ b/llvm/include/llvm/IR/GlobalValue.h @@ -79,15 +79,15 @@ 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,11 @@ /// definition cannot be runtime preempted. unsigned IsDSOLocal : 1; + 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 +282,12 @@ return IsDSOLocal; } + bool hasPartition() const { + return HasPartition; + } + StringRef getPartition() const; + void setPartition(StringRef Part); + static LinkageTypes getLinkOnceLinkage(bool ODR) { return ODR ? LinkOnceODRLinkage : LinkOnceAnyLinkage; } diff --git a/llvm/lib/AsmParser/LLLexer.cpp b/llvm/lib/AsmParser/LLLexer.cpp --- a/llvm/lib/AsmParser/LLLexer.cpp +++ b/llvm/lib/AsmParser/LLLexer.cpp @@ -570,6 +570,7 @@ KEYWORD(align); KEYWORD(addrspace); KEYWORD(section); + KEYWORD(partition); KEYWORD(alias); KEYWORD(ifunc); KEYWORD(module); diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp --- a/llvm/lib/AsmParser/LLParser.cpp +++ b/llvm/lib/AsmParser/LLParser.cpp @@ -956,6 +956,19 @@ GA->setUnnamedAddr(UnnamedAddr); maybeSetDSOLocal(DSOLocal, *GA); + 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()); @@ -1091,6 +1104,11 @@ 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; @@ -5272,6 +5290,7 @@ std::vector FwdRefAttrGrps; LocTy BuiltinLoc; std::string Section; + std::string Partition; unsigned Alignment; std::string GC; GlobalValue::UnnamedAddr UnnamedAddr = GlobalValue::UnnamedAddr::None; @@ -5288,6 +5307,8 @@ BuiltinLoc) || (EatIfPresent(lltok::kw_section) && ParseStringConstant(Section)) || + (EatIfPresent(lltok::kw_partition) && + ParseStringConstant(Partition)) || parseOptionalComdat(FunctionName, C) || ParseOptionalAlignment(Alignment) || (EatIfPresent(lltok::kw_gc) && @@ -5389,6 +5410,7 @@ Fn->setUnnamedAddr(UnnamedAddr); Fn->setAlignment(Alignment); Fn->setSection(Section); + Fn->setPartition(Partition); Fn->setComdat(C); Fn->setPersonalityFn(PersonalityFn); if (!GC.empty()) Fn->setGC(GC); diff --git a/llvm/lib/AsmParser/LLToken.h b/llvm/lib/AsmParser/LLToken.h --- a/llvm/lib/AsmParser/LLToken.h +++ b/llvm/lib/AsmParser/LLToken.h @@ -113,6 +113,7 @@ kw_align, kw_addrspace, kw_section, + kw_partition, kw_alias, kw_ifunc, kw_module, diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp --- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -2976,6 +2976,9 @@ } inferDSOLocal(NewGV); + if (Record.size() > 15) + NewGV->setPartition(StringRef(Strtab.data() + Record[14], Record[15])); + return Error::success(); } @@ -3065,6 +3068,9 @@ } inferDSOLocal(Func); + 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 @@ -3142,6 +3148,12 @@ NewGA->setDSOLocal(getDecodedDSOLocal(Record[OpNum++])); inferDSOLocal(NewGA); + 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(); diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp --- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -1259,7 +1259,8 @@ 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)); @@ -1271,6 +1272,8 @@ 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; } @@ -1308,6 +1311,8 @@ 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); @@ -1330,6 +1335,8 @@ 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); @@ -1348,6 +1355,8 @@ 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(); } diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -1605,6 +1605,24 @@ 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); diff --git a/llvm/lib/IR/AsmWriter.cpp b/llvm/lib/IR/AsmWriter.cpp --- a/llvm/lib/IR/AsmWriter.cpp +++ b/llvm/lib/IR/AsmWriter.cpp @@ -3233,6 +3233,12 @@ 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(); @@ -3284,6 +3290,12 @@ writeOperand(IS, !isa(IS)); } + if (GIS->hasPartition()) { + Out << ", partition \""; + printEscapedString(GIS->getPartition(), Out); + Out << '"'; + } + printInfoComment(*GIS); Out << '\n'; } @@ -3424,6 +3436,11 @@ 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(); diff --git a/llvm/lib/IR/Globals.cpp b/llvm/lib/IR/Globals.cpp --- a/llvm/lib/IR/Globals.cpp +++ b/llvm/lib/IR/Globals.cpp @@ -67,6 +67,7 @@ setUnnamedAddr(Src->getUnnamedAddr()); setDLLStorageClass(Src->getDLLStorageClass()); setDSOLocal(Src->isDSOLocal()); + setPartition(Src->getPartition()); } void GlobalValue::removeFromParent() { @@ -180,6 +181,28 @@ return cast(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]; @@ -192,9 +215,8 @@ // Get or create a stable section name string and put it in the table in the // context. - if (!S.empty()) { - S = getContext().pImpl->SectionStrings.insert(S).first->first(); - } + if (!S.empty()) + S = getContext().pImpl->Saver.save(S); getContext().pImpl->GlobalObjectSections[this] = S; // Update the HasSectionHashEntryBit. Setting the section to the empty string diff --git a/llvm/lib/IR/LLVMContextImpl.h b/llvm/lib/IR/LLVMContextImpl.h --- a/llvm/lib/IR/LLVMContextImpl.h +++ b/llvm/lib/IR/LLVMContextImpl.h @@ -30,7 +30,6 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" -#include "llvm/ADT/StringSet.h" #include "llvm/BinaryFormat/Dwarf.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DebugInfoMetadata.h" @@ -41,6 +40,7 @@ #include "llvm/IR/TrackingMDRef.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/Casting.h" +#include "llvm/Support/StringSaver.h" #include "llvm/Support/YAMLTraits.h" #include #include @@ -1296,9 +1296,8 @@ Type X86_FP80Ty, FP128Ty, PPC_FP128Ty, X86_MMXTy; IntegerType Int1Ty, Int8Ty, Int16Ty, Int32Ty, Int64Ty, Int128Ty; - /// TypeAllocator - All dynamically allocated types are allocated from this. - /// They live forever until the context is torn down. - BumpPtrAllocator TypeAllocator; + BumpPtrAllocator Alloc; + UniqueStringSaver Saver{Alloc}; DenseMap IntegerTypes; @@ -1332,8 +1331,8 @@ /// Collection of per-GlobalObject sections used in this context. DenseMap GlobalObjectSections; - /// Stable collection of section strings. - StringSet<> SectionStrings; + /// Collection of per-GlobalValue partitions used in this context. + DenseMap GlobalValuePartitions; /// DiscriminatorTable - This table maps file:line locations to an /// integer representing the next DWARF path discriminator to assign to diff --git a/llvm/lib/IR/Type.cpp b/llvm/lib/IR/Type.cpp --- a/llvm/lib/IR/Type.cpp +++ b/llvm/lib/IR/Type.cpp @@ -255,7 +255,7 @@ IntegerType *&Entry = C.pImpl->IntegerTypes[NumBits]; if (!Entry) - Entry = new (C.pImpl->TypeAllocator) IntegerType(C, NumBits); + Entry = new (C.pImpl->Alloc) IntegerType(C, NumBits); return Entry; } @@ -307,7 +307,7 @@ if (Insertion.second) { // The function type was not found. Allocate one and update FunctionTypes // in-place. - FT = (FunctionType *)pImpl->TypeAllocator.Allocate( + FT = (FunctionType *)pImpl->Alloc.Allocate( sizeof(FunctionType) + sizeof(Type *) * (Params.size() + 1), alignof(FunctionType)); new (FT) FunctionType(ReturnType, Params, isVarArg); @@ -353,7 +353,7 @@ if (Insertion.second) { // The struct type was not found. Allocate one and update AnonStructTypes // in-place. - ST = new (Context.pImpl->TypeAllocator) StructType(Context); + ST = new (Context.pImpl->Alloc) StructType(Context); ST->setSubclassData(SCDB_IsLiteral); // Literal struct. ST->setBody(ETypes, isPacked); *Insertion.first = ST; @@ -379,7 +379,7 @@ return; } - ContainedTys = Elements.copy(getContext().pImpl->TypeAllocator).data(); + ContainedTys = Elements.copy(getContext().pImpl->Alloc).data(); } void StructType::setName(StringRef Name) { @@ -434,7 +434,7 @@ // StructType Helper functions. StructType *StructType::create(LLVMContext &Context, StringRef Name) { - StructType *ST = new (Context.pImpl->TypeAllocator) StructType(Context); + StructType *ST = new (Context.pImpl->Alloc) StructType(Context); if (!Name.empty()) ST->setName(Name); return ST; @@ -585,7 +585,7 @@ pImpl->ArrayTypes[std::make_pair(ElementType, NumElements)]; if (!Entry) - Entry = new (pImpl->TypeAllocator) ArrayType(ElementType, NumElements); + Entry = new (pImpl->Alloc) ArrayType(ElementType, NumElements); return Entry; } @@ -613,7 +613,7 @@ ->VectorTypes[std::make_pair(ElementType, NumElements)]; if (!Entry) - Entry = new (pImpl->TypeAllocator) VectorType(ElementType, NumElements); + Entry = new (pImpl->Alloc) VectorType(ElementType, NumElements); return Entry; } @@ -637,7 +637,7 @@ : CImpl->ASPointerTypes[std::make_pair(EltTy, AddressSpace)]; if (!Entry) - Entry = new (CImpl->TypeAllocator) PointerType(EltTy, AddressSpace); + Entry = new (CImpl->Alloc) PointerType(EltTy, AddressSpace); return Entry; } diff --git a/llvm/lib/MC/MCSectionELF.cpp b/llvm/lib/MC/MCSectionELF.cpp --- a/llvm/lib/MC/MCSectionELF.cpp +++ b/llvm/lib/MC/MCSectionELF.cpp @@ -152,6 +152,8 @@ OS << "llvm_linker_options"; else if (Type == ELF::SHT_LLVM_CALL_GRAPH_PROFILE) OS << "llvm_call_graph_profile"; + else if (Type == ELF::SHT_LLVM_SYMPART) + OS << "llvm_sympart"; else report_fatal_error("unsupported type 0x" + Twine::utohexstr(Type) + " for section " + getSectionName()); diff --git a/llvm/test/Bitcode/compatibility.ll b/llvm/test/Bitcode/compatibility.ll --- a/llvm/test/Bitcode/compatibility.ll +++ b/llvm/test/Bitcode/compatibility.ll @@ -160,6 +160,10 @@ @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 @@ @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 @ = [Linkage] [Visibility] ifunc , ; * @ @@ -271,6 +279,10 @@ @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.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) diff --git a/llvm/test/CodeGen/X86/partition.ll b/llvm/test/CodeGen/X86/partition.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/X86/partition.ll @@ -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" diff --git a/llvm/test/Object/X86/irsymtab.ll b/llvm/test/Object/X86/irsymtab.ll --- a/llvm/test/Object/X86/irsymtab.ll +++ b/llvm/test/Object/X86/irsymtab.ll @@ -9,7 +9,7 @@ ; BCA: blob data = '\x01\x00\x00\x00\x06\x00\x00\x00\x08\x00\x00\x00D\x00\x00\x00\x01\x00\x00\x00P\x00\x00\x00\x00\x00\x00\x00P\x00\x00\x00\x02\x00\x00\x00\x80\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\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' +; BCA-NEXT: blob data = '\x01\x00\x00\x00\x06\x00\x00\x00\x08\x00\x00\x00D\x00\x00\x00\x01\x00\x00\x00P\x00\x00\x00\x00\x00\x00\x00P\x00\x00\x00\x02\x00\x00\x00\x80\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\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' ; BCA-NEXT: ; BCA-NEXT: blob data = 'foobarproducerx86_64-unknown-linux-gnuirsymtab.ll'