From: Vedant Kumar Date: Fri, 25 Jan 2019 18:30:22 +0000 (+0000) Subject: [MC] Teach the MachO object writer about N_FUNC_COLD X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=6e7d0c8d17f880e3bdb673d2e2a3a565e3ddc8bc;p=llvm [MC] Teach the MachO object writer about N_FUNC_COLD N_FUNC_COLD is a new MachO symbol attribute. It's a hint to the linker to order a symbol towards the end of its section, to improve locality. Example: ``` void a1() {} __attribute__((cold)) void a2() {} void a3() {} int main() { a1(); a2(); a3(); return 0; } ``` A linker that supports N_FUNC_COLD will order _a2 to the end of the text section. From `nm -njU` output, we see: ``` _a1 _a3 _main _a2 ``` Differential Revision: https://reviews.llvm.org/D57190 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@352227 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/llvm/BinaryFormat/MachO.h b/include/llvm/BinaryFormat/MachO.h index 372fc902f77..08fe7803d40 100644 --- a/include/llvm/BinaryFormat/MachO.h +++ b/include/llvm/BinaryFormat/MachO.h @@ -334,6 +334,7 @@ enum { N_WEAK_DEF = 0x0080u, N_SYMBOL_RESOLVER = 0x0100u, N_ALT_ENTRY = 0x0200u, + N_COLD_FUNC = 0x0400u, // For undefined symbols coming from libraries, see GET_LIBRARY_ORDINAL() // as these are in the top 8 bits. SELF_LIBRARY_ORDINAL = 0x0, diff --git a/include/llvm/MC/MCDirectives.h b/include/llvm/MC/MCDirectives.h index e13a11b088e..4029264c202 100644 --- a/include/llvm/MC/MCDirectives.h +++ b/include/llvm/MC/MCDirectives.h @@ -19,6 +19,7 @@ enum MCSymbolAttr { MCSA_Invalid = 0, ///< Not a valid directive. // Various directives in alphabetical order. + MCSA_Cold, ///< .cold (MachO) MCSA_ELF_TypeFunction, ///< .type _foo, STT_FUNC # aka @function MCSA_ELF_TypeIndFunction, ///< .type _foo, STT_GNU_IFUNC MCSA_ELF_TypeObject, ///< .type _foo, STT_OBJECT # aka @object diff --git a/include/llvm/MC/MCSymbolMachO.h b/include/llvm/MC/MCSymbolMachO.h index 9f5cb0b5c6d..8f9ff56470a 100644 --- a/include/llvm/MC/MCSymbolMachO.h +++ b/include/llvm/MC/MCSymbolMachO.h @@ -34,6 +34,7 @@ class MCSymbolMachO : public MCSymbol { SF_WeakDefinition = 0x0080, SF_SymbolResolver = 0x0100, SF_AltEntry = 0x0200, + SF_Cold = 0x0400, // Common alignment SF_CommonAlignmentMask = 0xF0FF, @@ -97,6 +98,10 @@ public: return getFlags() & SF_AltEntry; } + void setCold() const { modifyFlags(SF_Cold, SF_Cold); } + + bool isCold() const { return getFlags() & SF_Cold; } + void setDesc(unsigned Value) const { assert(Value == (Value & SF_DescFlagsMask) && "Invalid .desc value!"); diff --git a/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index aed46d58f99..4c9fe59af42 100644 --- a/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -663,6 +663,9 @@ void AsmPrinter::EmitFunctionHeader() { if (MAI->hasDotTypeDotSizeDirective()) OutStreamer->EmitSymbolAttribute(CurrentFnSym, MCSA_ELF_TypeFunction); + if (F.hasFnAttribute(Attribute::Cold)) + OutStreamer->EmitSymbolAttribute(CurrentFnSym, MCSA_Cold); + if (isVerbose()) { F.printAsOperand(OutStreamer->GetCommentOS(), /*PrintType=*/false, F.getParent()); diff --git a/lib/MC/MCAsmStreamer.cpp b/lib/MC/MCAsmStreamer.cpp index cc473eae118..b18c82309ac 100644 --- a/lib/MC/MCAsmStreamer.cpp +++ b/lib/MC/MCAsmStreamer.cpp @@ -656,6 +656,9 @@ bool MCAsmStreamer::EmitSymbolAttribute(MCSymbol *Symbol, // .weak_reference case MCSA_WeakReference: OS << MAI->getWeakRefDirective(); break; case MCSA_WeakDefAutoPrivate: OS << "\t.weak_def_can_be_hidden\t"; break; + case MCSA_Cold: + // Assemblers currently do not support a .cold directive. + return false; } Symbol->print(OS, MAI); diff --git a/lib/MC/MCELFStreamer.cpp b/lib/MC/MCELFStreamer.cpp index 6954692a0ef..6fe16abd5a3 100644 --- a/lib/MC/MCELFStreamer.cpp +++ b/lib/MC/MCELFStreamer.cpp @@ -201,6 +201,7 @@ bool MCELFStreamer::EmitSymbolAttribute(MCSymbol *S, MCSymbolAttr Attribute) { // In the future it might be worth trying to make these operations more well // defined. switch (Attribute) { + case MCSA_Cold: case MCSA_LazyReference: case MCSA_Reference: case MCSA_SymbolResolver: diff --git a/lib/MC/MCMachOStreamer.cpp b/lib/MC/MCMachOStreamer.cpp index 7e368a8f1ad..613f255a4ea 100644 --- a/lib/MC/MCMachOStreamer.cpp +++ b/lib/MC/MCMachOStreamer.cpp @@ -386,6 +386,10 @@ bool MCMachOStreamer::EmitSymbolAttribute(MCSymbol *Sym, Symbol->setWeakDefinition(); Symbol->setWeakReference(); break; + + case MCSA_Cold: + Symbol->setCold(); + break; } return true; diff --git a/lib/MC/MCParser/AsmParser.cpp b/lib/MC/MCParser/AsmParser.cpp index 6c311c13836..189422e2ad3 100644 --- a/lib/MC/MCParser/AsmParser.cpp +++ b/lib/MC/MCParser/AsmParser.cpp @@ -426,6 +426,7 @@ private: DK_WEAK_DEFINITION, DK_WEAK_REFERENCE, DK_WEAK_DEF_CAN_BE_HIDDEN, + DK_COLD, DK_COMM, DK_COMMON, DK_LCOMM, @@ -1983,6 +1984,8 @@ bool AsmParser::parseStatement(ParseStatementInfo &Info, return parseDirectiveSymbolAttribute(MCSA_WeakReference); case DK_WEAK_DEF_CAN_BE_HIDDEN: return parseDirectiveSymbolAttribute(MCSA_WeakDefAutoPrivate); + case DK_COLD: + return parseDirectiveSymbolAttribute(MCSA_Cold); case DK_COMM: case DK_COMMON: return parseDirectiveComm(/*IsLocal=*/false); @@ -5223,6 +5226,7 @@ void AsmParser::initializeDirectiveKindMap() { DirectiveKindMap[".weak_definition"] = DK_WEAK_DEFINITION; DirectiveKindMap[".weak_reference"] = DK_WEAK_REFERENCE; DirectiveKindMap[".weak_def_can_be_hidden"] = DK_WEAK_DEF_CAN_BE_HIDDEN; + DirectiveKindMap[".cold"] = DK_COLD; DirectiveKindMap[".comm"] = DK_COMM; DirectiveKindMap[".common"] = DK_COMMON; DirectiveKindMap[".lcomm"] = DK_LCOMM; diff --git a/test/MC/AArch64/cold.s b/test/MC/AArch64/cold.s new file mode 100644 index 00000000000..44cb52fd794 --- /dev/null +++ b/test/MC/AArch64/cold.s @@ -0,0 +1,13 @@ +// RUN: llvm-mc -triple aarch64-apple-ios -o - -filetype=obj %s | \ +// RUN: llvm-readobj -symbols | FileCheck %s -check-prefix=READOBJ + +// READOBJ-LABEL: Name: cold_func +// READOBJ-NEXT: Type: Section +// READOBJ-NEXT: Section: __text +// READOBJ-NEXT: RefType: UndefinedNonLazy (0x0) +// READOBJ-NEXT: Flags [ (0x400) + + .text + .cold cold_func +cold_func: + ret diff --git a/test/tools/llvm-nm/AArch64/Inputs/cold-func.ll b/test/tools/llvm-nm/AArch64/Inputs/cold-func.ll new file mode 100644 index 00000000000..686e67e8de8 --- /dev/null +++ b/test/tools/llvm-nm/AArch64/Inputs/cold-func.ll @@ -0,0 +1,3 @@ +define void @cold_func() cold { + ret void +} diff --git a/test/tools/llvm-nm/AArch64/macho-cold.test b/test/tools/llvm-nm/AArch64/macho-cold.test new file mode 100644 index 00000000000..a07f5d27d14 --- /dev/null +++ b/test/tools/llvm-nm/AArch64/macho-cold.test @@ -0,0 +1,4 @@ +RUN: llc -O0 -mtriple=aarch64-apple-ios %p/Inputs/cold-func.ll -filetype=obj -o %t.aarch64.o +RUN: llvm-nm -m %t.aarch64.o | FileCheck %s + +CHECK: [cold] _cold_func diff --git a/tools/llvm-nm/llvm-nm.cpp b/tools/llvm-nm/llvm-nm.cpp index 08ea238ac3a..f81e909c924 100644 --- a/tools/llvm-nm/llvm-nm.cpp +++ b/tools/llvm-nm/llvm-nm.cpp @@ -554,6 +554,11 @@ static void darwinPrintSymbol(SymbolicFile &Obj, SymbolListT::iterator I, (NDesc & MachO::N_ALT_ENTRY) == MachO::N_ALT_ENTRY) outs() << "[alt entry] "; + if (Filetype == MachO::MH_OBJECT && + ((NType & MachO::N_TYPE) != MachO::N_UNDF) && + (NDesc & MachO::N_COLD_FUNC) == MachO::N_COLD_FUNC) + outs() << "[cold] "; + if ((NDesc & MachO::N_ARM_THUMB_DEF) == MachO::N_ARM_THUMB_DEF) outs() << "[Thumb] ";