diff --git a/llvm/include/llvm/MC/MCParser/MCAsmParserExtension.h b/llvm/include/llvm/MC/MCParser/MCAsmParserExtension.h --- a/llvm/include/llvm/MC/MCParser/MCAsmParserExtension.h +++ b/llvm/include/llvm/MC/MCParser/MCAsmParserExtension.h @@ -98,6 +98,8 @@ return getParser().parseOptionalToken(T); } + bool ParseDirectiveCGProfile(StringRef, SMLoc); + bool check(bool P, const Twine &Msg) { return getParser().check(P, Msg); } diff --git a/llvm/include/llvm/MC/MCWinCOFFStreamer.h b/llvm/include/llvm/MC/MCWinCOFFStreamer.h --- a/llvm/include/llvm/MC/MCWinCOFFStreamer.h +++ b/llvm/include/llvm/MC/MCWinCOFFStreamer.h @@ -64,6 +64,8 @@ unsigned ByteAlignment) override; void emitIdent(StringRef IdentString) override; void EmitWinEHHandlerData(SMLoc Loc) override; + void emitCGProfileEntry(const MCSymbolRefExpr *From, + const MCSymbolRefExpr *To, uint64_t Count) override; void finishImpl() override; /// \} @@ -73,6 +75,9 @@ void emitInstToData(const MCInst &Inst, const MCSubtargetInfo &STI) override; + void finalizeCGProfileEntry(const MCSymbolRefExpr *&S); + void finalizeCGProfile(); + private: void Error(const Twine &Msg) const; }; diff --git a/llvm/lib/MC/MCParser/COFFAsmParser.cpp b/llvm/lib/MC/MCParser/COFFAsmParser.cpp --- a/llvm/lib/MC/MCParser/COFFAsmParser.cpp +++ b/llvm/lib/MC/MCParser/COFFAsmParser.cpp @@ -70,6 +70,7 @@ addDirectiveHandler<&COFFAsmParser::ParseDirectiveLinkOnce>(".linkonce"); addDirectiveHandler<&COFFAsmParser::ParseDirectiveRVA>(".rva"); addDirectiveHandler<&COFFAsmParser::ParseDirectiveSymbolAttribute>(".weak"); + addDirectiveHandler<&COFFAsmParser::ParseDirectiveCGProfile>(".cg_profile"); // Win64 EH directives. addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartProc>( @@ -125,6 +126,7 @@ bool parseCOMDATType(COFF::COMDATType &Type); bool ParseDirectiveLinkOnce(StringRef, SMLoc); bool ParseDirectiveRVA(StringRef, SMLoc); + bool ParseDirectiveCGProfile(StringRef, SMLoc); // Win64 EH directives. bool ParseSEHDirectiveStartProc(StringRef, SMLoc); @@ -299,6 +301,10 @@ return false; } +bool COFFAsmParser::ParseDirectiveCGProfile(StringRef S, SMLoc Loc) { + return MCAsmParserExtension::ParseDirectiveCGProfile(S, Loc); +} + bool COFFAsmParser::ParseSectionSwitch(StringRef Section, unsigned Characteristics, SectionKind Kind) { diff --git a/llvm/lib/MC/MCParser/ELFAsmParser.cpp b/llvm/lib/MC/MCParser/ELFAsmParser.cpp --- a/llvm/lib/MC/MCParser/ELFAsmParser.cpp +++ b/llvm/lib/MC/MCParser/ELFAsmParser.cpp @@ -862,45 +862,8 @@ return false; } -/// ParseDirectiveCGProfile -/// ::= .cg_profile identifier, identifier, -bool ELFAsmParser::ParseDirectiveCGProfile(StringRef, SMLoc) { - StringRef From; - SMLoc FromLoc = getLexer().getLoc(); - if (getParser().parseIdentifier(From)) - return TokError("expected identifier in directive"); - - if (getLexer().isNot(AsmToken::Comma)) - return TokError("expected a comma"); - Lex(); - - StringRef To; - SMLoc ToLoc = getLexer().getLoc(); - if (getParser().parseIdentifier(To)) - return TokError("expected identifier in directive"); - - if (getLexer().isNot(AsmToken::Comma)) - return TokError("expected a comma"); - Lex(); - - int64_t Count; - if (getParser().parseIntToken( - Count, "expected integer count in '.cg_profile' directive")) - return true; - - if (getLexer().isNot(AsmToken::EndOfStatement)) - return TokError("unexpected token in directive"); - - MCSymbol *FromSym = getContext().getOrCreateSymbol(From); - MCSymbol *ToSym = getContext().getOrCreateSymbol(To); - - getStreamer().emitCGProfileEntry( - MCSymbolRefExpr::create(FromSym, MCSymbolRefExpr::VK_None, getContext(), - FromLoc), - MCSymbolRefExpr::create(ToSym, MCSymbolRefExpr::VK_None, getContext(), - ToLoc), - Count); - return false; +bool ELFAsmParser::ParseDirectiveCGProfile(StringRef S, SMLoc Loc) { + return MCAsmParserExtension::ParseDirectiveCGProfile(S, Loc); } namespace llvm { diff --git a/llvm/lib/MC/MCParser/MCAsmParserExtension.cpp b/llvm/lib/MC/MCParser/MCAsmParserExtension.cpp --- a/llvm/lib/MC/MCParser/MCAsmParserExtension.cpp +++ b/llvm/lib/MC/MCParser/MCAsmParserExtension.cpp @@ -7,6 +7,8 @@ //===----------------------------------------------------------------------===// #include "llvm/MC/MCParser/MCAsmParserExtension.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCContext.h" using namespace llvm; @@ -17,3 +19,44 @@ void MCAsmParserExtension::Initialize(MCAsmParser &Parser) { this->Parser = &Parser; } + +/// ParseDirectiveCGProfile +/// ::= .cg_profile identifier, identifier, +bool MCAsmParserExtension::ParseDirectiveCGProfile(StringRef, SMLoc) { + StringRef From; + SMLoc FromLoc = getLexer().getLoc(); + if (getParser().parseIdentifier(From)) + return TokError("expected identifier in directive"); + + if (getLexer().isNot(AsmToken::Comma)) + return TokError("expected a comma"); + Lex(); + + StringRef To; + SMLoc ToLoc = getLexer().getLoc(); + if (getParser().parseIdentifier(To)) + return TokError("expected identifier in directive"); + + if (getLexer().isNot(AsmToken::Comma)) + return TokError("expected a comma"); + Lex(); + + int64_t Count; + if (getParser().parseIntToken( + Count, "expected integer count in '.cg_profile' directive")) + return true; + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + + MCSymbol *FromSym = getContext().getOrCreateSymbol(From); + MCSymbol *ToSym = getContext().getOrCreateSymbol(To); + + getStreamer().emitCGProfileEntry( + MCSymbolRefExpr::create(FromSym, MCSymbolRefExpr::VK_None, getContext(), + FromLoc), + MCSymbolRefExpr::create(ToSym, MCSymbolRefExpr::VK_None, getContext(), + ToLoc), + Count); + return false; +} diff --git a/llvm/lib/MC/MCWinCOFFStreamer.cpp b/llvm/lib/MC/MCWinCOFFStreamer.cpp --- a/llvm/lib/MC/MCWinCOFFStreamer.cpp +++ b/llvm/lib/MC/MCWinCOFFStreamer.cpp @@ -328,7 +328,34 @@ llvm_unreachable("not implemented"); } +void MCWinCOFFStreamer::emitCGProfileEntry(const MCSymbolRefExpr *From, + const MCSymbolRefExpr *To, + uint64_t Count) { + // Ignore temporary symbols for now. + if (!From->getSymbol().isTemporary() && !To->getSymbol().isTemporary()) + getAssembler().CGProfile.push_back({From, To, Count}); +} + +void MCWinCOFFStreamer::finalizeCGProfileEntry(const MCSymbolRefExpr *&SRE) { + const MCSymbol *S = &SRE->getSymbol(); + bool Created; + getAssembler().registerSymbol(*S, &Created); + if (Created) { + cast(S)->setIsWeakExternal(); + cast(S)->setExternal(true); + } +} + +void MCWinCOFFStreamer::finalizeCGProfile() { + for (MCAssembler::CGProfileEntry &E : getAssembler().CGProfile) { + finalizeCGProfileEntry(E.From); + finalizeCGProfileEntry(E.To); + } +} + void MCWinCOFFStreamer::finishImpl() { + finalizeCGProfile(); + MCObjectStreamer::finishImpl(); } diff --git a/llvm/lib/MC/WinCOFFObjectWriter.cpp b/llvm/lib/MC/WinCOFFObjectWriter.cpp --- a/llvm/lib/MC/WinCOFFObjectWriter.cpp +++ b/llvm/lib/MC/WinCOFFObjectWriter.cpp @@ -154,6 +154,8 @@ MCSectionCOFF *AddrsigSection; std::vector AddrsigSyms; + MCSectionCOFF *CGProfileSection = nullptr; + WinCOFFObjectWriter(std::unique_ptr MOTW, raw_pwrite_stream &OS); @@ -674,6 +676,13 @@ Asm.registerSection(*AddrsigSection); } + if (!Asm.CGProfile.empty()) { + CGProfileSection = Asm.getContext().getCOFFSection( + ".llvm.call-graph-profile", COFF::IMAGE_SCN_LNK_REMOVE, + SectionKind::getMetadata()); + Asm.registerSection(*CGProfileSection); + } + // "Define" each section & symbol. This creates section & symbol // entries in the staging area. for (const auto &Section : Asm) @@ -1099,6 +1108,20 @@ } } + // Create the contents of the .llvm.call-graph-profile section. + if (CGProfileSection) { + auto *Frag = new MCDataFragment(CGProfileSection); + Frag->setLayoutOrder(0); + raw_svector_ostream OS(Frag->getContents()); + for (const MCAssembler::CGProfileEntry &CGPE : Asm.CGProfile) { + uint32_t FromIndex = CGPE.From->getSymbol().getIndex(); + uint32_t ToIndex = CGPE.To->getSymbol().getIndex(); + OS.write((const char *)&FromIndex, sizeof(uint32_t)); + OS.write((const char *)&ToIndex, sizeof(uint32_t)); + OS.write((const char *)&CGPE.Count, sizeof(uint64_t)); + } + } + assignFileOffsets(Asm, Layout); // MS LINK expects to be able to use this timestamp to implement their diff --git a/llvm/test/MC/AsmParser/directive_cgprofile.s b/llvm/test/MC/AsmParser/directive_cgprofile.s --- a/llvm/test/MC/AsmParser/directive_cgprofile.s +++ b/llvm/test/MC/AsmParser/directive_cgprofile.s @@ -1,5 +1,5 @@ # RUN: llvm-mc -triple i386-unknown-unknown %s | FileCheck %s - +# RUN: llvm-mc -triple x86_64-pc-win32 %s | FileCheck %s .cg_profile a, b, 32 .cg_profile freq, a, 11 .cg_profile freq, b, 20 diff --git a/llvm/test/MC/COFF/cgprofile.s b/llvm/test/MC/COFF/cgprofile.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/COFF/cgprofile.s @@ -0,0 +1,119 @@ +# RUN: llvm-mc -filetype=obj -triple x86_64-pc-win32 %s -o %t +# RUN: llvm-readobj -S --symbols --sd --cg-profile %t | FileCheck %s + + .section .test,"w" +a: + + .cg_profile a, b, 32 + .cg_profile freq, a, 11 + .cg_profile late, late2, 20 + .cg_profile .L.local, b, 42 + + .globl late +late: +late2: .word 0 +late3: +.L.local: + +# CHECK: Name: .llvm.call-graph-profile +# CHECK-NEXT: VirtualSize: +# CHECK-NEXT: VirtualAddress: +# CHECK-NEXT: RawDataSize: 48 +# CHECK-NEXT: PointerToRawData: +# CHECK-NEXT: PointerToRelocations: +# CHECK-NEXT: PointerToLineNumbers: +# CHECK-NEXT: RelocationCount: +# CHECK-NEXT: LineNumberCount: +# CHECK-NEXT: Characteristics [ (0x100800) +# CHECK-NEXT: IMAGE_SCN_ALIGN_1BYTES (0x100000) +# CHECK-NEXT: IMAGE_SCN_LNK_REMOVE (0x800) +# CHECK-NEXT: ] +# CHECK-NEXT: SectionData ( +# CHECK-NEXT: 0000: 0A000000 0E000000 20000000 00000000 +# CHECK-NEXT: 0010: 11000000 0A000000 0B000000 00000000 +# CHECK-NEXT: 0020: 0B000000 0C000000 14000000 00000000 +# CHECK-NEXT: ) + +# CHECK: Symbols [ +# CHECK: Name: a +# CHECK-NEXT: Value: +# CHECK-NEXT: Section: .test +# CHECK-NEXT: BaseType: +# CHECK-NEXT: ComplexType: +# CHECK-NEXT: StorageClass: Static +# CHECK-NEXT: AuxSymbolCount: +# CHECK: Name: late +# CHECK-NEXT: Value: +# CHECK-NEXT: Section: .test +# CHECK-NEXT: BaseType: +# CHECK-NEXT: ComplexType: +# CHECK-NEXT: StorageClass: External +# CHECK-NEXT: AuxSymbolCount: +# CHECK: Name: late2 +# CHECK-NEXT: Value: +# CHECK-NEXT: Section: .test +# CHECK-NEXT: BaseType: +# CHECK-NEXT: ComplexType: +# CHECK-NEXT: StorageClass: Static +# CHECK-NEXT: AuxSymbolCount: +# CHECK: Name: late3 +# CHECK-NEXT: Value: +# CHECK-NEXT: Section: .test +# CHECK-NEXT: BaseType: +# CHECK-NEXT: ComplexType: +# CHECK-NEXT: StorageClass: Static +# CHECK-NEXT: AuxSymbolCount: +# CHECK: Name: b +# CHECK-NEXT: Value: +# CHECK-NEXT: Section: IMAGE_SYM_UNDEFINED +# CHECK-NEXT: BaseType: +# CHECK-NEXT: ComplexType: +# CHECK-NEXT: StorageClass: WeakExternal +# CHECK-NEXT: AuxSymbolCount: 1 +# CHECK-NEXT: AuxWeakExternal { +# CHECK-NEXT: Linked: .weak.b.default.late +# CHECK-NEXT: Search: Alias +# CHECK-NEXT: } +# CHECK: Name: .weak.b.default.late +# CHECK-NEXT: Value: +# CHECK-NEXT: Section: IMAGE_SYM_ABSOLUTE +# CHECK-NEXT: BaseType: +# CHECK-NEXT: ComplexType: +# CHECK-NEXT: StorageClass: External +# CHECK-NEXT: AuxSymbolCount: 0 +# CHECK: Name: freq +# CHECK-NEXT: Value: +# CHECK-NEXT: Section: IMAGE_SYM_UNDEFINED +# CHECK-NEXT: BaseType: +# CHECK-NEXT: ComplexType: +# CHECK-NEXT: StorageClass: WeakExternal +# CHECK-NEXT: AuxSymbolCount: 1 +# CHECK-NEXT: AuxWeakExternal { +# CHECK-NEXT: Linked: .weak.freq.default.late +# CHECK-NEXT: Search: Alias +# CHECK-NEXT: } +# CHECK: Name: .weak.freq.default.late +# CHECK-NEXT: Value: +# CHECK-NEXT: Section: IMAGE_SYM_ABSOLUTE +# CHECK-NEXT: BaseType: +# CHECK-NEXT: ComplexType: +# CHECK-NEXT: StorageClass: External +# CHECK-NEXT: AuxSymbolCount: 0 + +# CHECK: CGProfile [ +# CHECK-NEXT: CGProfileEntry { +# CHECK-NEXT: From: a +# CHECK-NEXT: To: b +# CHECK-NEXT: Weight: 32 +# CHECK-NEXT: } +# CHECK-NEXT: CGProfileEntry { +# CHECK-NEXT: From: freq +# CHECK-NEXT: To: a +# CHECK-NEXT: Weight: 11 +# CHECK-NEXT: } +# CHECK-NEXT: CGProfileEntry { +# CHECK-NEXT: From: late +# CHECK-NEXT: To: late2 +# CHECK-NEXT: Weight: 20 +# CHECK-NEXT: } +# CHECK-NEXT: ] \ No newline at end of file