]> granicus.if.org Git - llvm/commitdiff
Add IR support, ELF section and user documentation for partitioning feature.
authorPeter Collingbourne <peter@pcc.me.uk>
Wed, 29 May 2019 03:29:01 +0000 (03:29 +0000)
committerPeter Collingbourne <peter@pcc.me.uk>
Wed, 29 May 2019 03:29:01 +0000 (03:29 +0000)
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

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@361923 91177308-0d34-0410-b5e6-96231b3b80d8

19 files changed:
docs/Extensions.rst
include/llvm/BinaryFormat/ELF.h
include/llvm/IR/GlobalValue.h
lib/AsmParser/LLLexer.cpp
lib/AsmParser/LLParser.cpp
lib/AsmParser/LLToken.h
lib/Bitcode/Reader/BitcodeReader.cpp
lib/Bitcode/Writer/BitcodeWriter.cpp
lib/CodeGen/AsmPrinter/AsmPrinter.cpp
lib/IR/AsmWriter.cpp
lib/IR/Globals.cpp
lib/IR/LLVMContextImpl.h
lib/MC/MCParser/ELFAsmParser.cpp
lib/MC/MCSectionELF.cpp
lib/Object/ELF.cpp
test/Bitcode/compatibility.ll
test/CodeGen/X86/partition.ll [new file with mode: 0644]
test/MC/ELF/section.s
test/Object/X86/irsymtab.ll

index 8543ac611850605a477727041d71c4e173eee893..e6f7fdd50447bb52c621b058557612c5dd65d3b3 100644 (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
 ------------------
 
index 6ec924d08d1066d997cd286ec404b3901492ef10..8258bb3711bfd921bf111ca4baab2013e8cdedde 100644 (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.
index d78ce622bc5dd099a4b6e91d29b1759b7ac0c1f0..2209881dbda6221fd810df3b3fd7fbc954f9b7c9 100644 (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;
   }
index c0b9cd12d0c0fb20d8ba73851ed3fb142c176fa9..dc8ff7f13150554f6b1df212aebadc0b50b7339f 100644 (file)
@@ -570,6 +570,7 @@ lltok::Kind LLLexer::LexIdentifier() {
   KEYWORD(align);
   KEYWORD(addrspace);
   KEYWORD(section);
+  KEYWORD(partition);
   KEYWORD(alias);
   KEYWORD(ifunc);
   KEYWORD(module);
index 6af084edbd8c906ac46d54c78f7038d29086590e..28a8480e7d3dc5faff5066af54bc1157ef3790bb 100644 (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);
index 33ea28bb10e830a3652d71472b78da166c14304c..a1e709321787779bb3bc5d5d7c458e864d67c75e 100644 (file)
@@ -113,6 +113,7 @@ enum Kind {
   kw_align,
   kw_addrspace,
   kw_section,
+  kw_partition,
   kw_alias,
   kw_ifunc,
   kw_module,
index 412f99d5e6266ae495c8495c2d01104bd91e6cd8..b23115ba31d4f54f7330dfbea1256d361ed71a71 100644 (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();
index 7d9b0583d1e1f58b8bfd8d241df98bdc481a202d..00d6fe8e27c467a47a4856287e7b44dcbe1ebf61 100644 (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();
   }
index bf7776b1dc0001522f36507f5d033c29255f2152..3317952d05d0a48d64cb931c81c444257ffb7aa7 100644 (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);
index b5db8bdeb2272846f3d7e69682ddbf23224a289e..ca7afd0d81aa0ed68256186a468429d9e691e770 100644 (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();
index b3fdcc6a5fc9c7d9bc4a5b66bd644c170d3f4de4..e2bfc0420bc53657b0b939978ae3e8b2b015c505 100644 (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];
index e977f05110991bc76aa24a5c3fd9ad93778399a2..4560617624ea5b8a6f6aabadc548b62c81e768c4 100644 (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.
index 48ced8d3dfa9cb6409bae14e71dfbe5706a7ed79..a55bdd5364cb76d7a6a648d6a1a596183acb525a 100644 (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");
   }
index 569b6ba099747ab5d311868ee24d34fa6d197b82..efe504b2024c71bd6d03b9796ac8114a8b05232a 100644 (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());
index 951f4ae8f7eeac9a71d0d912fcd4f011423c455d..a9c90e01551eaa1e39f5c35307f8f436f0f1cd3b 100644 (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);
index a1474df6d941df6ca8ca49caf245f7aa7870b616..6c3a6887346e082b9a0385bae1842ce2d9e6b736 100644 (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)
diff --git a/test/CodeGen/X86/partition.ll b/test/CodeGen/X86/partition.ll
new file mode 100644 (file)
index 0000000..cc8d44e
--- /dev/null
@@ -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"
index 7c9bb7915d1af196751aa893ee6928651aff02db..f4ed666bfc71de4bbd1c161e3b08fe41d309f42e 100644 (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: }
index 1b9915a2b745ef03adc8c501a7824192b5ac132c..2e7b189572f69a809bb207b42de3e4ef89f53336 100644 (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'